mybatis一级缓存和二级缓存的区别及说明
目录
- 结论
- 源码
- 一级缓存
- 二级缓存
我们通常说mybatis中一级缓存是sqlSession级别的,二级缓存是namespace级别的,这篇笔记主要来记录下这么说的原理
结论
先说结论吧,一级缓存之所以说是sqlSession级别的,是因为一级缓存的数据是存放在了sqlSession的一个内部属性中,所以,每次openSession()开启一个sqlSession之后,一级缓存就会失效
二级缓存之所以可以跨sqlSession,是因为二级缓存的数据,是存放在mappedStatement对象中的一个内部属性中,这里说的内部属性其实不太准确,但是先忽略,后面会详细解释
我们知道,mybatis在启动的时候,会解析全局配置文件,会把mapper.xml文件中的一个个sql片段,解析成一个个mappedStatement对象,所以,这里二级缓存自然也就是namespace级别的
源码
在mybatis源码中,CachingExecutor是二级缓存的处理类,BaseExecutor是一级缓存的处理类
我们先来看一级缓存的处理
一级缓存
这里是一级缓存的处理,会发现,这里是从localCache中根据key获取value的,换而言之,这里的localCache大概率就是我们所谓的一级缓存了,我们看下localCache是在哪里赋值的
可以看到,localCache是在BaseExecutor的构造函数中,每次new 出来的,所以,这里我们可以知道,只要new 一个BaseExecutor对象,就会有一个localCache,那对应的一级缓存就不一样,我们再看下,在正常的sql执行过程中,BaseExecutor是在什么时候初始化的
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSession()
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource
org.apache.ibatis.session.Configuration#newExecutor()
这里可以看到,在通过openSession()初始化sqlSession对象的时候,就会初始化一个executor对象
所以,我们说一级缓存是executor级别的
二级缓存
我们接着来看二级缓存的逻辑
二级缓存是从这里的tcm这个对象中来获取的,但是实际上,我们调到tcm.getObject()方法中,会发现实际上是从入参的cache来获取的,所以我们需要看下这里入参的cache是从哪里获取到的
可以看到这个方法的第一行,是从MappedStatement对象中获取到的
可以看到,mappedStatement对象是从configuration对象中获取到,所以我们要看下configuration的mappedStatement对象是什么时候赋值的
org.apache.ibatis.builder.MapperBuilderAssistant#addMappedStatement()
在这个方法中,可以看到,最终会把statement对象设置的configuration中,同时需要注意的是,我们用到的cache对象是从currentCache来的,所以我们需要关注,currentCache是从哪里来的?
在同类中,org.apache.ibatis.builder.MapperBuilderAssistant#useNewCache
这个方法中,会给currentCache赋值
如果看过前面两篇关于mybatis源码解析博客的,应该会比较清楚,这里的useNewCache()方法,就是在解析mapper.xml文件中的节点时,调用的
org.apache.ibatis.builder.xml.XMLMapperBuilder#configurationElement
org.apache.ibatis.builder.xml.XMLMapperBuilder#cacheElement
org.apache.ibatis.builder.MapperBuilderAssistant#useNewCache
截图中的这个方法是解析一个mapper.xml的逻辑
所以,我们发现
在解析mapper.xml文件的时候,会解析配置的节点,在解析这个节点的时候,会初始化一个cache对象,这个cache对象,会赋值给currentCache然后继续解析一个个sql片段,这一个mapper.xml文件中,无论有多少个sql,这里的currentCache都是一样的二级缓存在使用的时候,会从mappedStatement对象中获取currentCache,如果currentCache不为null,就表示需要使用二级缓存然后从currentCache,根据key获取value这里需要知道的是:这里的currentCache,也是对PerpetualCache的包装,以前文章有介绍过,这次不做过多的解读
所以,我们说二级缓存是namespace级别的
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。