MyBatis缓存机制
学习了关于Mybatis的一级缓存、二级缓存相关的知识,做一下总结…
一级缓存:
mybatis中一级缓存是一种基于sqlSession
的缓存(是默认开启的,并且是无法关闭的,不过可以在select标签中的flushCache设置为true,使得查询都清除缓存)。
一级缓存失效情况:
- 不同sqlsession会导致一级缓存失效
- 同一个sqlsession,但是查询条件不同
- 同一个sqlsession,两次查询中间执行了增删改操作
- 同一个sqlsession,手动清楚了sqlsession(opensession.clearCache())
二级缓存
mybatis的二级缓存是基于namespace
的,及每个映射文件作为一个域(默认打开,不过要在对应的mapper文件设置cache标签才能生效),在会话关闭后,一级缓存的数据会被保存到二级缓存中,当再一次访问时先从二级查询,找到后缓存到当前会话中,找不到再到一级缓存查询,如果还是没命中就到数据库。
- 开启操作:
<!--全局配置文件设置-->
<setting name="cacheEnabled" value="true/>
<!--mapper文件设置-->
<mapper namespace="要实现接口名全限名">
<cache eviction=""
flushInterval=""
readOnly=""
size=""
type="">
缓存原理图:
当会话关闭,一级缓存的数据会被保存到二级缓存 缓存顺序:二级缓存->一级缓存->数据库
mybatis提供了缓存接口:package org.apache.ibatis.cache
大致流程:在会话关闭后,一级缓存的数据会被保存到二级缓存中。当再一次访问时先从二级查询,命中后缓存到当前会话中(一级),没命中再到一级缓存查询,如果还是没命中就到数据库。
总结:
一级:
- MyBatis一级缓存使用没有容量限制的HashMap,比较简陋;
- statement级别的缓存每一次查询后清除;
- session级别缓存在同一个SqlSession的insert、update、delete操作之前清除;
- MyBatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为
Statement
(默认)
<setting name="localCacheScope" value="STATEMENT"/>
二级:
- 二级缓存的有效范围是namespace,缓存的加载和失效均在事务提交之后生效,使用cache-ref标签可以实现多个namespace共享缓存;
- 二级缓存可以根据statement标签的useCache和flushCache 细粒度的控制是否需要使用缓存和强制刷新缓存
- 二级缓存的实现相对于一级缓存有明显增强,但是依然是本地实现,解决了多个SqlSession共享缓存的问题,但是仍然无法应用于分布式环境;
- 由于是基于namespace的缓存,如果存在多表查询,可能存在数据更新之后此namespace下的缓存还没有失效,也会产生脏数据(多个namespace对同一张表查询)
解决:通过使用Cache ref
来实现两个映射文件对应的sql操作都是同一块缓存
<cache-ref namespace="全限名"/>
注意:
不熟悉mybatis缓存机制最好不要使用,否则会出现脏数据情况,可以使用第三方缓存如redis。
参考:
https://mp.weixin.qq.com/s/auovRTFk7NjJKthqrZwbMQ
https://tech.meituan.com/2018/01/19/mybatis-cache.html
一些操作配置相关:
https://blog.youkuaiyun.com/qq_26525215/article/details/79182637