概述
- 二级缓存基于mapper的namespace,mabytis默认不开启二级缓存
- 二级缓存有一个二级缓存区域,按照namespace分吗,如果两个mapper的namespace相同,那么这两个mapper共用同一个缓存区域
- 多个sqlSession可以共享一个二级缓存
- 更新操作清除缓存
- 底层HashMap实现
- 如果你的MyBatis使用了二级缓存,并且你的Mapper和select语句也配置使用了二级缓存,那么在执行select查询的时候,MyBatis会先从二级缓存中取输入,其次才是一级缓存。
- mybatis的二级缓存是通过CacheExecutor实现的。CacheExecutor其实是Executor的代理对象。所有的查询操作,在CacheExecutor中都会先匹配缓存中是否存在,不存在则查询数据库。
开启缓存的配置
- mybatis配置文件中配置全局使用缓存,默认是true
<settings>
<!-- 这个配置使全局的映射器启用或禁用缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>
- 在mapper.xml中开启二缓存,mapper.xml下的sql执行完成会存储到它的缓存区,默认是不开启
<cache
eviction="FIFO"
flushInterval="60000"
size="1024"
readOnly="true"/>
- Mapper XML文件配置支持cache后,文件中所有的Mapper statement就支持了。此时要个别对待某条,需要:
<select id="inetAton" parameterType="string" resultType="integer" useCache=“false”>
select inet_aton(#{name})
</select>
mapper中配置的参数说明:
-
eviction
(可用的收回策略)默认为 LRU
-
LRU
– 最近最少使用的:移除最长时间不被使用的对象。
-
FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。
-
SOFT
– 软引用:移除基于垃圾回收器状态和软引用规则的对象。
-
WEAK
– 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
-
flushInterval
(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
-
size
(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值1024。
-
readOnly
(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。
开启缓存后说明:
- 所有在映射文件里的select 语句都将被缓存。
- 所有在映射文件里insert,update 和delete 语句会清空缓存。
- 缓存使用“最近很少使用”算法来回收
- 缓存不会被设定的时间所清空。
- 每个缓存可以存储1024 个列表或对象的引用(不管查询出来的结果是什么)。
- 缓存将作为“读/写”缓存,意味着获取的对象不是共享的且对调用者是安全的。不会有其它的调用
注意的几个细节
- mapper配置中,如果readOnly为false,此时要结果集对象是可序列化的。
<cache readOnly="false"/>
- 在SqlSession未关闭之前,如果对于同样条件进行重复查询,此时采用的是local session cache,而不是上面说的这些cache。
- MyBatis缓存查询到的结果集对象,而非结果集数据,是将映射的PO对象集合缓存起来。
- 二级缓存是跨sqlsession的基于mapper级别的缓存,而sqlsession可以使用多个对象,但是多个对象必须要访问同一个mapper下的sql语句时
缺陷
- mybatis的缓存天生不支持分布式,需要整合其他第三方缓存库
- 基于mapper的命名空间(namespace),这样会存在一个隐患,如果不能保证一个表的数据,只缓存在一个mapper中,就可能会造成数据混乱,因为会在两个namespace中都存在一份缓存。