Mybatis一级缓存是会话级的缓存,而二级缓存则是应用级别的缓存,默认关闭,二级缓存使用不慎可能会导致脏读。
application.properties添加配置
mybatis.configuration.cache-enabled=true
在mapper的xml文件中的namespace中加上
<cache></cache>
为了方便看到效果 ,application.properties设置日志级别为debug
logging.com.qs.birp.dao=debug
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
先测试调用一次SQL ,再次调用时可以缓存命中。
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3563659a] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.qs.birp.dao.EquTAufkDao]: 0.3333333333333333
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3563659a]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@d18d986] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.qs.birp.dao.EquTAufkDao]: 0.5
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@d18d986]
和一级缓存不同,二级缓存在事务提交和会话关闭后才会写入(在会话和二级缓存间会有一个事务缓存管理器TransactionalCacheManager,会话期间查询的数据会放到管理器的暂存区TransactionalCache,当事务提交后才会写入到指定的二级缓存区域),当执行数据库update操作时会清空该namespace下的缓存。
源码位置:org.apache.ibatis.executor.CachingExecutor.java 这里面比较关键的代码是List list = (List) tcm.getObject(cache, key);
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
Mybatis源码里面二级缓存使用装饰器的设计模式,装饰器在org.apache.ibatis.cache.decorators包下面。
SynchronizedCache 同步锁,用于保证对指定缓存区的操作都是同步的
LoggingCache 统计器,记录缓存命中率
BlockingCache 阻塞器,基于key加锁,防止缓存穿透
ScheduledCache 时效检查,用于验证缓存有效器,并清除无效数据
LruCache 溢出算法,最近最少使用算法,淘汰闲置最久的缓存。
FifoCache 溢出算法,淘汰加入时间最久的缓存
WeakCache 溢出算法,基于java弱引用规则淘汰缓存
SoftCache 溢出算法,基于java软引用规则淘汰缓存
PerpetualCache 实际存储,内部采用HashMap进行存储。