mybatis 二级缓存源码阅读
二级缓存
二级缓存之所以能够跨session是因为采用的装饰器模式对Executor进行了装饰.
// 配置文件中开启总开关 <setting name="cacheEnabled" value="true" />
Mapper文件中开启二级缓存 <cache eviction="LRU" flushInterval="600000" size="1024" readOnly="true"/>
image-20200623111635652.png
//获取一个session
SqlSession sqlSession1 = sqlSessionFactory.openSession();
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
//获取一个执行器
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
}
Configuration
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
//设置默认的执行器
executor = new SimpleExecutor(this, transaction);
//判断setting标签中 cacheEnabled是否为true从而开启2级缓存总开关
if (cacheEnabled) {
//用了装饰器模式
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
SqlSession
这是很关键的一点,正式因为这段代码使得二级缓存跟mapper的namespace绑定
statement就是Mapper类名+方法名字
@Override
//执行select查询
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
//获取mapper对应的
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
CachingExecutor
判断对应的mapper是否开启2级缓存的地方
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
//判断这个ms是否设置了缓存 对应Mapper中的 <Cache/>标签
Cache cache = ms.getCache();
if (cache != null) {
...
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}