内置二级查询缓存
myBatis 查询缓存的作用域是根据映射文件 mapper 的 namespace 划分的,相同
namespace 的 mapper 查询数据存放在同一个缓存区域。不同 namespace 下的数据互不干扰。无论是一级缓存还是二级缓存,都是按照 namespace 进行分别存放的。
但一、二级缓存的不同之处在于,Sq|Session 一旦关闭,则 SqISession 中的数据将不存在,即一级缓存就不覆存在。而二级缓存的生命周期会与整个应用同步,与 SqISession 是否关闭无关。
使用二级缓存的目的,不是共享数据,因为 MyBatis 从缓存中读取数据的依据是 SQL 的 id,而非查询出的对象。所以,二级缓存中的数据不是为了在多个查询之间共享(所有查询中只要查询结果中存在该对象的,就直接从缓存中读取,这是对数据的共享,Hibernate 中的缓存就是为了共享,但MyBaits的不是),而是为了延长该查询结果的保存时间,提高系统性能。
myBatis 内置的二二级缓存为 org.apache.ibatis.cache.impl.PerpetualCache。项目:MyBatis_Cache_SecondLevel_BuildIn。在 MyBatis_Cache_SqlSession 基础上进行修改。
二级缓存用法
二级查询缓存的使用很简单,只需要完成两步即可:
(1)实体序列化
要求查询结果所涉及到的实体类要实现 java.io.Serializable 接口。若该实体类存在父类,或其具有域属性,则父类与域属性类也要实现序列化接口。
![]()
(2)mapper 映射中添加<cache/>标签
在 mapper 映射文件的<mapper/>标签中添加<cache/>子标签。
![]()
(3)二级缓存的配置
为<cache/>标签添加一些相关属性设置,可以对二级缓存的运行性能进行控制。当然,若不指定设置,则均保持默认值。
![]()
① eviction:逐出策略。当二级缓存中的对象达到最大值时,就需要通过逐出策略将缓存中的对象移出缓存。默认为LRU。常用的策略有;
● FIFO: First In First Out,先进先出。
● LRU: Least Recently Used,未被使用时间最长的。
② flushInterval:刷新缓存的时间间隔,单位毫秒。这里的刷新缓存即清空缓存。一般不指
定,即当执行增删改时刷新缓存。
③ readOnly:设置缓存中数据是否只读。只读的缓存会给所有调用者返回缓存对象的相同
实例,因此这些对象不能被修改,这提供了很重要的性能优势。但读写的缓存会返回缓存对象的拷贝。这会慢-一些,但是安全,因此默认是 false。
④ size:级缓存中可以存放的最多对象个数。默认为 1024 个。
二级查询缓存的存在性证明
对于映射文件中的同一个查询,肯定是同一个namespace中的查询( 因为就是同一个查询 )。在一次查询后,将 Sq|Session 关闭,再进行一次相同查询,发现并没有到 DB 中进行 select 查询。说明二级查询缓存是存在的。
(1)修改测试类
![]()
(2)查看控制台
CacheHit Ratio 表示缓存命中率。开启二级缓存后,每执行一次查询,系统都会计算一次二级缓存的命中率。第一次查询也是先从缓存中查询,只不过缓存中一定是没有的。所以会再从 DB 中查询。由于二级缓存中不存在该数据,所以命中率为0。但第二次查询是从二级缓存中读取的,所以这一次的命中率为 1/2=0.5 。当然,若有第三次查询的话,则命中率会是 1/3= 0.66。
![]()
增删改对二级查询缓存的影响
(1)默认对缓存的刷新
增删改操作,无论是否进行提交 sqlSession.commit(),均会清空一级、二级查询缓存,使查询再次从 DB 中 select。
A、修改测试类
![]()
B、查看控制台
注意,在第二次查询时的缓存命中率为 0.5,但还是从 DB 中查询了。说明在缓存中与该查询相对应的 key 是存在的,但是 value 呗清空。而 value 被清空的原因是前面执行了对 DB 的增删改操作,所以不会从缓存中直接将 null 值返回,而是从 DB 中进行查询。
![]()
(2)设置增删改操作不刷新二级缓存
若要使某个增、删或改操作不清空二级缓存,则需要在<insert/>或</delete>或<update/>中添加属性 flushCache="false",默认为 true。
![]()
二级缓存的关闭
二级缓存默认为开启状态。若要将其关闭,则需要进行相关设置。
根据关闭的范围大小,可以分为全局关闭与局部关闭。
(1)全局关闭
所为全局关闭是指,整个应用的二级缓存全部关闭,所有查询均不使用二级缓存。全局开关设置在主配置文件的全局设置</settings>中,该属性为 cacheEnabled,设置为 false ,则关闭;设置为 true ,则开启,默认值为 true。即二级缓存默认是开启的。
![]()
(2)局部关闭
所谓局部关闭是指,整个应用的二级缓存是开启的,但只是针对于某个<select/>查询,不使用二级缓存。此时可以单独只关闭该<select/>标签的又级缓存。
在该要关闭二级缓存的<select/>标签中,将其属性 useCache 设置为 false ,即可关闭该查询的二级缓存。该属性默认为 true ,即每个<select/>查询的二级缓存默认是开启的。
![]()
- 二级缓存的使用原则
① 只能在一个命名空间下使用二级缓存
由于二级缓存中的数据是基于 namespace 的,即不同 namespace 中的数据互不干扰。在多个 namespace 中若均存在对同一个表的操作,那么这多个 namespace 中的数据可能就会出现不一致现象。
② 在单表上使用二级缓存
如果一个表与其它表有关联关系,那么就非常有可能存在多个 namespace 对同一数据的操作。而不同 namespace 中的数据互不干扰,所以有可能出现这多个 namespace 中的数据不一致现象。
③ 查询多于修改时使用二级缓存
在查询操作远远多于增删改操作的情况下可以使用二级缓存。因为任何增删改操作都将刷新二级缓存,对二级缓存的频繁刷新将降低系统性能。
网友评论