博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Mybatis 源码学习(四) 二级缓存
阅读量:4217 次
发布时间:2019-05-26

本文共 4616 字,大约阅读时间需要 15 分钟。

听说二级缓存是Mapper级的,我找变了mapper也没有找到。

不小心看到MappedStatement有个cache属性。难道是在这里。开始没能串起来。只能网上找。

最后确认这个二级缓存果然就是在MappedStatement。而它又是在Configuration上的啊,这不就成了全局的了吗。

猜:只是缓存的时候以mapper为一个组,然后清理的时候按mapper去清理缓存。所以就成了是Mapper级的了。也就是说是以Mapper去管理这个缓存的。

找的过程就不详细记录了。

要知道二级缓存是可以设置开关的,而且除了全局的开关,还可以在具体的mapper里单独设置。怎么实现的呢?

还有具体查的时候,怎么查的MappedStatement中的cache呢?

还是从最简单的DefaultSqlSession的selectOne(String statement) 方法开始看起。

@Override  public 
List
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 
List
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
list = (List
) tcm.getObject(cache, key); if (list == null) { list = delegate.
query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);//缓存中没有再去BaseExcutor中查(二级缓存没有再找一级缓存) tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } return delegate.
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.在配置文件中天津配置

2.Mapper中添加配置 最简单的配置还可以配置 最大缓存数量 刷新时间 移除策略

3.如果有某个statement不想用二级缓存的话 就可以添加一个配置 这个配置默认为true,只用不使用时才配置

补充一下我的测试代码,开始一直看不到二级缓存到底是怎么生效的,测试代码更让人迷惑,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

你可能感兴趣的文章
唐巧总结的40个国人iOS技术博客
查看>>
谈 UIView Animation 编程艺术
查看>>
谈谈ios传值方式(属性传值、代理传值、Block传值、单例传值、通知传值、KVC传值)
查看>>
ios 数组最大值,最小值,平均值,和的快速算法
查看>>
ios 让UITextField(输入框)直接进入编辑状态
查看>>
如何优雅的谈论Objective-C
查看>>
ios 自定义返回按钮侧滑失效完美解决方案
查看>>
深入理解Objective-C Runtime
查看>>
深入理解RunLoop
查看>>
ios 应用内跳转微信
查看>>
iOS上如何让按钮文本左对齐问题
查看>>
Xcode8 兼容iOS 10 整理笔记
查看>>
iOS 枚举的巧用
查看>>
让你的 Xcode8 继续使用插件
查看>>
iOS去除导航栏和tabbar的1px横线
查看>>
iOS GitHub上常用第三方框架
查看>>
ios 隐藏cell分割线和自定义cell分割线颜色
查看>>
ios 图片保存到系统相册
查看>>
UIAlertController样式集合
查看>>
数据结构之—图
查看>>