MyBatis 缓存实现原理
标签(空格分隔): mybatis
缓存概述
- mybatis存在一级缓存和二级缓存
- 一级缓存在BaseExecutor中实现,二级缓存在CachingExecutor中实现。
- mybatis缓存采用了装饰器和委托模式。(LoggingCache、SynchronizedCache是其装饰类)
- 一级缓存和二级缓存都存放在PerpetualCache对象中,PerpetualCache持有一个Map<Object, Object> Cache属性
Key为CacheKey,Value为sql执行后的结果集。CacheKey 根据namespace、offset、limit、sql输个属性生成。 - 二级缓存支持其他缓存介质接入。
立即开始
***Mapper.xml 配置中加入,这里启用了二级缓存。
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
- evication 表示缓存采用的淘汰策略,flushInterval表示缓存的刷新时间,size表示缓存数量到达多大时刷新,readOnly则表示缓存是否只读。
- 在mybatis初始化时会把mapper.xml解析成StatementMapper对象,StatementMapper维护一个cache对象,二级缓存是和StatementMapper绑定在一起的。
代码
- 从上面的包名和类名我们可以看出,mybatis的缓存采用了装饰器模式。委托模式在CachingExecutor类中能看出来。
一级缓存
-
一级缓存在BaseExecutor类中实现,在152行中,如果返回结果不为空,并且能在localCache中get到数据,mybatis就不会再去查询数据库。 其中的localCache是一个PerpetualCache对象。
-
由于BaseExecutor是BatchExecutor、ReuseExecutor、SimpleExecutor的父类。在执行查询(query)时,mybatis都会判断localCache是否存在缓存,如果存在就返回缓存中的值。言外之意就是一级缓存是默认开启的。
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
} -
CachingExecutor 实现了二级缓存,interceptorChain在这里实现了Executor级别的拦截,返回了一个被代理得执行器对象。CachingExecutor持有了一个BaseExecutor的委托对象,这里就是委托模式得运用。