sqlserver 相同语句 缓存_MyBatis 缓存的使用,看这篇就够了

在日常工作中,我们大多使用MyBatis的默认缓存配置,但是MyBatis缓存机制也有一些不足之处,一不留神就会出现脏数据,形成一些潜在的隐患,后续排查问题容易浪费时间精力。

所以,如何用好MyBatis的缓存,是重中之重的。这里主要介绍MyBatis 的一级缓存和二级缓存。

在默认的情况下, 只开启一级缓存(一级缓存是对同一个 SqlSession 而言的)。

1 一级缓存

同一个 SqlSession 对象, 在参数和 SQL 完全一样的情况下, 只执行一次 SQL 语句(如果缓存没有过期) 也就是只有在参数和SQL 完全一样的情况下, 才会有这种情况。

原理图如下:一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构用于存储缓存数据。不同的sqlSession之间的缓存数据区域是互相不影响的。也就是他只能作用在同一个sqlSession中,不同的sqlSession中的缓存是互相不能读取的。

7573722f2df63f3a29c9fd1ce192ec0b.png

1.1 同一个 SqlSession

55283b871c4ec714a239fbc522035d4b.png

在以上的代码中, 进行了两次查询, 使用相同的 SqlSession, 结果如下

在日志和输出中:第一次查询发送了 SQL 语句, 后返回了结果;第二次查询没有发送 SQL 语句, 直接从内存中获取了结果。而且两次结果输入一致, 同时断言两个对象相同也通过。

1.2 不同的 SqlSession

c2b29007e1ed274febec4f426e2864a7.png

在代码中, 分别使用 sqlSessionsqlSession2 进行了相同的查询。其结果如下

d12dadb410fb12be149b762a2f461c40.png

从日志中可以看到两次查询都分别从数据库中取出了数据。 虽然结果相同, 但两个是不同的对象。

1.3 刷新缓存

刷新缓存是清空这个 SqlSession 的所有缓存, 不单单是某个键。

f49f89e5395ab91493f53edbf2bbc81e.png

如果是以上, 没什么不同, 结果还是第二个不发 SQL 语句。在此, 做一些修改, 在 StudentMapper.xml 中, 添加

e7330d9a5f84120030958a81e5d85af4.png

修改后的配置文件如下:

91add1e702238ab2c4a52df97fbcadfd.png

结果如下:

030ef3173679751d6f3d4a21d14a378e.png

第一次, 第二次都发送了 SQL 语句, 同时, 断言两个对象相同出错。

1.4 总结

在同一个 SqlSession 中, MyBatis 会把执行的方法和参数通过算法生成缓存的键值, 将键值和结果存放在一个 Map 中, 如果后续的键值一样, 则直接从 Map 中获取数据;

不同的 SqlSession 之间的缓存是相互隔离的;

用一个 SqlSession, 可以通过配置使得在查询前清空缓存;

任何的 UPDATE, INSERT, DELETE 语句都会清空缓存。

2 二级缓存

二级缓存存在于 SqlSessionFactory 生命周期中。二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。UserMapper有一个二级缓存区域(按namespace分),其它mapper也有自己的二级缓存区域(按namespace分)。每一个namespace的mapper都有一个二级缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中。

959275558c594d0a920bd80b09d50465.png

2.1 配置二级缓存

2.1.1 全局开关

在 MyBatis 中, 二级缓存有全局开关和分开关, 全局开关, 在 MyBatis-config.xml 中如下配置:

e696940f493c8cb151036c32f3122f15.png

默认是为 true, 即默认开启总开关。

2.1.2 分开关

分开关就是说在 *Mapper.xml 中开启或关闭二级缓存, 默认是不开启的。

2.1.3 entity 实现序列化接口

2.2 使用二级缓存

bff409802c3408db72d460bc4e1e56aa.png

结果如下:

83e2a9a1f8750c2d3f67a36573e0c5c6.png

以上结果, 分几个过程解释:第一阶段:

在第一个 SqlSession 中, 查询出 student 对象, 此时发送了 SQL 语句;

student更改了name 属性;

SqlSession 再次查询出 student1 对象, 此时不发送 SQL 语句, 日志中打印了 「Cache Hit Ratio」, 代表二级缓存使用了, 但是没有命中。 因为一级缓存先作用了。

由于是一级缓存, 因此, 此时两个对象是相同的。

调用了 sqlSession.close(), 此时将数据序列化并保持到二级缓存中。

第二阶段:

新创建一个 sqlSession.close() 对象;

查询出 student2 对象,直接从二级缓存中拿了数据, 因此没有发送 SQL 语句, 此时查了 3 个对象,但只有一个命中, 因此 命中率 1/3=0.333333;

查询出 student3 对象,直接从二级缓存中拿了数据, 因此没有发送 SQL 语句, 此时查了 4 个对象,但只有一个命中, 因此 命中率 2/4=0.5;

由于 readOnly=“false”, 因此 student2 和 student3 都是反序列化得到的, 为不同的实例。

看到这里的小伙伴,如果你喜欢这篇文章的话,别忘了转发、收藏、留言互动!

如果对文章有任何问题,欢迎在留言区和我交流~

最近我新整理了一些资料,包含面经分享、模拟试题、和视频干货,如果你需要的话,欢迎私信我!

f6453d0ac1941dc2c256924500e33893.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值