mybatis源码阅读之6:mybatis缓存

mybaits含有一个非常强大的查询缓存功能,可以非常方便的定制。

mybatis默认定义了两级缓存:一级缓存和二级缓存

1.默认情况下,只有一级缓存开启(SqlSession级别的缓存,也成为本地缓存)。

2.二级缓存需要手动开启和配置,他是基于namespace级别的缓存(全局缓存)

3.为了提高扩展性,mybatis定义了缓存接口Cache,我们可以通过实现Cache接口来自定义二级缓存。

一级缓存:

前提是在同一个sqlSession中,并且查询条件完全一样才能生效。

例如:

XXXMapper mapper = openSession.getMapper(XXXMapper.class);

XXX xx1 = mapper.getById(1);
XXX xx2 = mapper.getById(1);

 

此时,因为mapper是在同一个sqlSession中,所以xx2是从缓存中取出的,也就是xx1==xx2

XXXMapper mapper1 = openSession1.getMapper(XXXMapper.class);
XXX xx1 = mapper1.getById(1);

XXXMapper mapper2 = openSession2.getMapper(XXXMapper.class);
XXX xx2 = mapper2.getById(1);

如果mapper不是同一个sqlSession中,例如上面的代码,分别是从openSession1中和openSession2中获取的mapper,那么xx1是不等于xx2的,因为都是从数据库查询所得,并不是同一个对象。(这里说的不是同一个对象,不等,不要用重写hashCode啥的去钻牛角尖哈)

一级缓存失效的四种情况:

  • 1.sqlSession不同
  • 2.查询条件不同
  • 3.sqlSession相同,但是两次查询中间有增删改操作
  • 4.sqlSession相同,但是手动清空了一级缓存(openSession.clearCache())

二级缓存:

基于namespace级别的缓存,一个namespace对应一个二级缓存。

工作机制:

1.一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;

2.如果会话关闭,一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存的内容

3.不同namespace查询的数据会放在自己对应的缓存中(map),比如,查询student和teacher,数据都会放在自己的namespace中

使用步骤:

1.开启全局二级缓存配置

<setting name="cacheEnabled" value="true"/>

配置信息,最好都显示配置,因为不同版本的默认值可能不同

2.在mapper.xml中配置使用二级缓存

<cache></cache>

二级缓存有各种策略对用不同场景,如:

<cache eviction="" flushInterval="" readOnly="" size="" type=""></cache>

下面具体说一下各属性的意思:

eviction:缓存的回收

  • LRU – 最近最少使用的:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
  • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

flushInterval:(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒 形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。

readOnly:(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓 存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存 会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因此默认是 false。

size:(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的 可用内存资源数目。默认值是 1024。

type:除了这些自定义缓存的方式, 你也可以通过实现你自己的缓存或为其他第三方缓存方案 创建适配器来完全覆盖缓存行为。

           其中,缓存的pojo对象要实现序列化接口。

再说一次:二级缓存生效,是在会话关闭并且开启了二级缓存的情况下才可以的。

下面接着说一下和缓存相关的设置:

1.cacheEnabled=false,关闭二级缓存,一级缓存仍然有效【针对全局】。

2.select标签中useCache=false,不使用二级缓存,一级缓存仍然有效【针对指定sql】。

3.每个增删改标签中的flushCache=true,一级缓存,二级缓存都会被清楚。增删改执行完就会清楚缓存。

4.sqlSession.clearCache(),只会清除一级缓存,和二级缓存无关。

5.localCacheScope,一级缓存作用域。MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速      重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地会话仅    用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。

下面借用一下别人的图来看一下一级缓存和二级缓存:

1.一级缓存都是对sqlSession而言。

2.二级缓存都是基于namespace而言。

3.在开启二级缓存的情况下,一个查询,先看看对用的二级缓存有没有数据,然后再决定是取缓存还是查库。

猜你喜欢

转载自blog.csdn.net/licwzy/article/details/87372347