为什么Mybatis一级和二级缓存都不建议使用?(一)
缓存是在哪起作用的?
个人认为mybatis一级缓存和二级缓存并不是一个很好的设计,工作中我基本上也不会使用一级缓存和二级缓存,因为一旦使用不当会造成很多问题,所以我们今天就来看看到底会有什么问题?
上一节我们介绍了Executor会调用StatementHandler执行sql,起一个承上启下的作用。
Executor的设计是一个典型的装饰者模式,SimpleExecutor,ReuseExecutor是具体实现类,而CachingExecutor是装饰器类。
可以看到具体组件实现类有一个父类BaseExecutor,而这个父类是一个模板模式的典型应用,操作一级缓存的操作都在这个类中,而具体的操作数据库的功能则让子类去实现。
「二级缓存则是一个装饰器类,当开启二级缓存的时候,会使用CachingExecutor对具体实现类进行装饰,所以查询的时候一定是先查询二级缓存再查询一级缓存」
「那么一级缓存和二级缓存有什么区别呢?」
一级缓存
// BaseExecutor
protected PerpetualCache localCache;
一级缓存是BaseExecutor中的一个成员变量localCache(对HashMap的一个简单封装),因此一级缓存的生命周期与SqlSession相同,如果你对SqlSession不熟悉,你可以把它类比为JDBC编程中的Connection,即数据库的一次会话。
「一级缓存和二级缓存key的构建规则是一致的,都是一个CacheKey对象,因为Mybatis中涉及动态SQL等多方面的因素,缓存的key不能仅仅通过String来表示」
当执行sql的如下4个条件都相等时,CacheKey才会相等
- mappedStatment的id
- 指定查询结构集的范围
- 查询所使用SQL语句
- 用户传递给SQL语句的实际参数值
「当查询的时候先从缓存中查询,如果查询不到的话再从数据库中查询」
org.apache.ibatis.executor.BaseExecutor#query
当使用同一个SqlSession执行更新操作时,会先清空一级缓存。因此一级缓存中内容被使用的概率也很低
一级缓存测试
「看到美团技术团队上关于一级缓存和二级缓存的一些测试写的挺不错的,就直接引用过来了」
原文地址:https://tech.meituan.com/2018/01/19/mybatis-cache.html 测试代码github地址:https://github.com/kailuncen/mybatis-cache-demo
接下来通过实验,了解MyBatis一级缓存的效果,每个单元测试后都请恢复被修改的数据。
首先是创建示例表student,创建对应的POJO类和增改的方法,具体可以在entity包和mapper包中查看。
CREATE TABLE `student` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(200) COLLATE utf8_bin DEFAULT NULL,
`age` tinyint(3) unsigned DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
在以下实验中,id为1的学生名称是凯伦
「实验1」
开启一级缓存,范围为会话级别,调用三次getStudentById,代码如下所示:
执行结果:
我们可以看到,只有第一次真正查询了数据库,后续的查询使用了一级缓存。
「实验2」
增加了对数据库的修改操作,验证在一次数据库会话中,如果对数据库发生了修改操作,一级缓存是否会失效。
执行结果:
我们可以看到,在修改操作后执行的相同查询,查询了数据库,一级缓存失效。
文章转自公众号:Java识堂