Mybatis 源码学习(四) 二级缓存
听说二级缓存是Mapper级的,我找变了mapper也没有找到。
不小心看到MappedStatement有个cache属性。难道是在这里。开始没能串起来。只能网上找。
最后确认这个二级缓存果然就是在MappedStatement。而它又是在Configuration上的啊,这不就成了全局的了吗。
猜:只是缓存的时候以mapper为一个组,然后清理的时候按mapper去清理缓存。所以就成了是Mapper级的了。也就是说是以Mapper去管理这个缓存的。
找的过程就不详细记录了。
要知道二级缓存是可以设置开关的,而且除了全局的开关,还可以在具体的mapper里单独设置。怎么实现的呢?
还有具体查的时候,怎么查的MappedStatement中的cache呢?
还是从最简单的DefaultSqlSession的selectOne(String statement) 方法开始看起。
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
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();
}
}
这executor.query 有两个实现类。一个是CachingExecutor,另一个是BaseExecutor。我们看CachingExecutor的query
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();//从MappedStatement中获取cache。这里我们就知道从这里获取的二级缓存,之前的推测正确,二级缓存就是MappedStatement的cache。
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {//这里的isUseCache是在Mapper文件中设置的缓存开关
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);//缓存中没有再去BaseExcutor中查(二级缓存没有再找一级缓存)
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
这里我们就弄明白了,如何从二级缓存中去数据了。
那么这个executor到底是CachingExecutor还是BaseExecutor呢?
那就要看SqlSession中的executor是如何被创建的
来看这个newExecutor方法,这是我看到的最有价值的一个方法。
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) {//全局设置,是否开启二级缓存,这样看来如果全局关闭,mapper中怎么设置都无法生效啊!
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
开始以为ExecutorType里会有CachingExecutor呢。后来发现不是这里的这个type并不是。
这里有BaseExecutor、SimleExecutor、ReuseExecutor、BatchExecutor、CachingExecutor,是什么关系呢。
SimleExecutor、ReuseExecutor、BatchExecutor是BaseExecutor的子类,CachingExecutor感觉更像是个代理类。
关于二级缓存呢,就看有没有套CachingExecutor这个代理类,跟三个子类没有关系。
二级缓存的开启:
1.在配置文件中天津配置
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
2.Mapper中添加配置 最简单的配置还可以配置 最大缓存数量 刷新时间 移除策略
<cache/>
3.如果有某个statement不想用二级缓存的话 就可以添加一个配置 这个配置默认为true,只用不使用时才配置
<select id="selectUser" resultMap="UserMapper" parameterType="Long" useCache="false">
补充一下我的测试代码,开始一直看不到二级缓存到底是怎么生效的,测试代码更让人迷惑,debug看就是找不到。
public static void main( String[] args )
{
String resource = "mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("selectUser",1L);
sqlSession.commit(); //这里从网上看到的,的确是不加commit不行,还以为存到别的地方了呢。
SqlSession sqlSession1 = sqlSessionFactory.openSession();
sqlSession1.selectOne("selectUser",1L);
user.setName("autotester1");
sqlSession.update("updateUserName",user);
user = sqlSession.selectOne("selectUser",1L);
System.out.println(user.getName());
//UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//System.out.println(userMapper);
} catch (IOException e) {
e.printStackTrace();
}
}
关键在那个commit,之前没有commit,怎么也不生效。
二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。
从这里学到的:https://www.cnblogs.com/xdp-gacl/p/4270403.html
还没有评论,来说两句吧...