注:Mybatis的版本是3.5.0。
上一篇分析了一级缓存,这篇来分析二级缓存。
以下的内容,跳过了很多细节,可以去看这篇博客。
一级缓存只能在同一个SqlSession中共享,而二级缓存则可以在多个SqlSession中共享。
开启二级缓存,那么使用的是CachingExecutor和SimpleExecutor(不修改默认设置的情况下),如下List-1所示,SimpleExecutor是封装在CachingExecutor中的。
List-1
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) {
//将SimpleExecutor封装起来
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
CachingExecutor使用了委托模式,其属性"Executor delegate",
List-2
package org.apache.ibatis.executor;
......
/**
* @author Clinton Begin
* @author Eduardo Macarron
*/
public class CachingExecutor implements Executor {
private final Executor delegate;
private final TransactionalCacheManager tcm = new TransactionalCacheManager();
public CachingExecutor(Executor delegate) {
this.delegate = delegate;
delegate.setExecutorWrapper(this);
}
......
如下图1所示,CachingExecutor中使用的Cache是SynchronizedCache,它里面还封装了很多Cache,最终数据是存储在PerpetualCache中,是个HashMap。
图1 CachingExecutor中使用的Cache是SynchronizedCache
由于二级缓存Cache封装在SynchronizedCache中,所以对二级缓存的操作是线程安全的,SynchronizedCache的几乎每个方法上都加了Sychronized,这在实现线程安全的同时,也在一定程度上成了瓶颈,特别是对二级缓存操作的线程数量很多时。
在List-2中的属性tcm,这个是理解二级缓存的一个关键点。
private final TransactionalCacheManager tcm = new TransactionalCacheManager();
session1提交后,session2才能看到session1缓存的结果。