缓存
一级缓存
MyBatis使用SqlSession对象表示一次数据库的会话,MyBatis会话级别的数据缓存称为一级数据缓存,简称一级缓存。默认启用。
SqlSession是MyBatis的一个门面接口,SqlSession将它的工作交给了Executor执行器这个角色来完成,负责完成对数据库的各种操作。当创建了一个SqlSession对象(DefaultSqlSession)时,MyBatis会为这个SqlSession对象创建一个新的Executor(BaseExecutor,SimpleExecutor,BatchExecutor,ResueExecutor)执行器,而缓存信息Cache(PerpetualCache)就被维护在这个Executor执行器中,MyBatis将缓存和对缓存相关的操作封装成了Cache接口中。
DefaultSqlSession持有一个Executor(executor),BaseExecutor持有一个PerpetualCache(localCache),PerpetualCache持有一个HashMap<Object, Object>(cache),一级缓存就是存在cache中
MyBatis根据如下4种数据计算并构建CacheKey对象, 作为一级缓存的key值
statementId(mapper的id),rowBounds(分页),传递给JDBC的SQL(参数是"?"),传递给JDBC的参数值("?"的值)
rowBounds:查询时要求的结果集中的结果范围 (结果的范围通过rowBounds.offset和rowBounds.limit表示)
一级缓存的生命周期
- 当会话结束时,SqlSession对象及其内部的Executor对象还有Executor对象内部的PerpetualCache对象会一并释放掉。
- 如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象(localCache=null),一级缓存将不可用
- 如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据(localCache.cache.clear()),但是该对象仍可使用
- SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据(在executor对象执行doUpdate()之前先执行clearLocalCache()),但是该对象可以继续使用
二级缓存
二级缓存是Mapper级别的缓存, 支持跨SqlSession访问, 相同的SQL查询两次, 只查询一次数据库。
如果开启二级缓存,sqlsession被关闭后,会把该sqlsession一级缓存中的数据添加到mapper的namespace的二级缓存中。这样,缓存在sqlsession关闭之后依然存在。
默认使用自带的PerpetualCache,但功能比较弱,能够配置第三方缓存
<cache/>
添加如上配置即可开启二级缓存,具有如下效果
- Mapper文件中的所有 select 语句的结果将会被缓存。
- Mapper文件中的所有 insert、update 和 delete 语句会刷新缓存。
- 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
- 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
- 缓存会保存列表或对象的1024个引用。
- 缓存会被视为读/写缓存(可读写的缓存会通过序列化返回缓存对象的拷贝),这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
这个配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的(认为返回的对象是只读的(其实可以修改),而不是技术上实现了无法修改),因此对它们进行修改可能会在不同线程中的调用者产生冲突。
eviction:剔除策略
- LRU – 最近最少使用:移除最长时间不被使用的对象。默认
- FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
- SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
- WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。
size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。
readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例,因此这些对象不能被修改(需人工保证),这就提供了可观的性能提升。可读写的缓存会(通过序列化)返回缓存对象的拷贝,速度上会慢一些,但是更安全,因此默认值是 false。