赞
踩
在前一篇文章中学习了Mybatis的一级和二级缓存,了解了一级缓存针对的是单个SqlSession而二级缓存则可以在多个SqlSession中共享,所以我们通常也称其为全局缓存。今天我们继续学习Mybatis的二级缓存。
public static void main(String[] args) throws Exception { String resource = "mybatis-config.xml"; //读取mybatis配置文件并获取输入流 InputStream inputStream = Resources.getResourceAsStream(resource); //构建SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); try (SqlSession session = sqlSessionFactory.openSession(); SqlSession session2 = sqlSessionFactory.openSession()) { PersonMapper mapper = session.getMapper(PersonMapper.class); //先查询一次 Person person = mapper.selectById(1L); System.out.println(person); session.commit(); //换个SqlSession再查一次 PersonMapper mapper1 = session2.getMapper(PersonMapper.class); mapper1.selectById(1L); System.out.println(person); } }
1、在探究二级缓存是如何创建之前,我们先要知道二级缓存是什么(这里说的是什么,指的是什么类),紧接着上一篇文章的的源码,我们可以看到Mybatis是从tcm这个对象(类是TransactionCaches:事务缓存),我们Debug一下这个类。
可以看出来这是一个很典型的装饰器设计模式,特点一层嵌套一层。可以看到最底层就是我们熟悉PerpetualCache,同时在此基础上又包装上了LruCache(提供了缓存换出功能)、然后包装了(SerializedCache:序列化缓存,所以如果想使用二级缓存,被缓存的对象一定要实现序列化接口)等等。
所以这个问题的答案就很明显了,二级缓存的底层数据结构为HashMap,由一个名为PerpetualCache的类封装,并在此基础上添加了一系列的装饰器。
知道了二级缓存是什么,接下来我们看他是如何被创建的。不知道你是否还记得之前写的文章里介绍了我们Configuration,也就是Mybatis的配置类,在那一篇文章中我们讲述了Mybatis是如何把我们编写的Xml封装成Configuration的对象(如果忘记了,可以回头瞄一眼)。因为Configuration中包含有Cache相关属性,所以我们推断Cache应该是同Configuration一起创建的。在XMLMapperBuilder中有这么一个方法,用于解析Cache
继续Debug该方法,可以看出Mybatis通过BuilderAssistant类构建了一个Cache对象 哦了,继续Debug
builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);这个方法
这里的代码也比较容易理解,就是通过建造者设计模式来构建一个Cache,并且添加到Configuration对象中。至此我们已经知道了Mybatis的二级缓存是如何被创建的了。
在一开始看到这个问题时,我毫不犹豫的认为一级缓存是优先于二级缓存执行的(毕竟一级之后才二级),但是在分析过源码之后才发现这样的认识是错误的,很多时候我们不能凭感觉去猜测,更多的是要结合源码。
源码分析:可以看到当我们开启二级缓存的时候,查询一开始会进入CachingExecutor的Query方法,如果能直接命中缓存则从缓存中返回数据,否则会通过委托类(这里是BaseExecutor)进行Query,接下来我们进入BaseExecutor类中。
这个代码就太熟悉了,这里不做过多介绍。所以得出结论,当二级缓存生效的情况下,Mybatis会先查询二级缓存如果二级缓存没有命中,则再去查询一级缓存。
因为二级缓存可以被多个SqlSession共享,话不多说直接Debug。
我们第一个查询,MappedStatment是@1738,此时Cache为@1749
第二个MappedStatment@1738,此时Cache也是@1749
所以可以说明对于多个SqlSession用的是同一个Cache。
这里直接给出答案,可以。
借用上面的图,可以看出二级缓存最终是封装了PerpetualCache,而PerpetualCache的底层又是HashMap。
key是 com.cmxy.mapper.PersonMapper也就是我们所写的Mapper文件的nameSpace。(这又可以证明上面的问题,多个mapper是可以共用同一个Cache的,只要设置对应的nameSpace即可)而Value则是一个名为Cache的对象。我们继续看这个Cache对象
该Cache也是一个类似于Map的结构,其中key为
-312300504:-769787714:com.cmxy.mapper.PersonMapper.selectById:0:2147483647:select * from t_person where id = ?:1:development
分解一下就是
multiplier:乘法因子,默认37
hashCode:哈希值,本例中是 -312300504
checkSum:表示所有更新对象baseHashCode的和 ,本例中是-769787714
updateList:本次查询相关参数; nameSpace+方法名+分页参数+具体SQL+SQL参数+环境(这里是develop,对应配置文件里的environment节点)
Value:是一个byte数组,也就是我们查询出来放在缓存中的对象序列化之后的产物。
今天我们进一步的学习了Mybatis的二级缓存,下一篇文章将会继续探究Mybatis的二级缓存。当然也是二级缓存的结束篇,希望对你有所帮助,
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。