为什么要用缓存?
MyBatis 的缓存
Mybatis的一级缓存和二级缓存执行顺序
一级缓存工作原理:
操作过程:
总结
二级缓存实现原理
图解:
cache属性的简介:
操作过程:
禁用二级缓存:
flushCache标签:刷新缓存(清空缓存)
二级缓存应用场景
注意事项
为什么要用缓存?
如果缓存中有数据,就不用从数据库获取,大大提高系统性能。
MyBatis 的缓存
MyBatis 的缓存分为一级缓存和二级缓存
- 一级缓存是对同一个 SqlSession 而言的,默认开启一级缓存
- 二级缓存放对同一个命名空间而言,默认是不打开的,使用二级缓存属性类需要实现 Serializable 序列化接口(可用来保存对象的状态),可在它的映射文件中配置<cache/>
Mybatis的一级缓存和二级缓存执行顺序
- 1、先判断二级缓存是否开启,如果没开启,再判断一级缓存是否开启,如果没开启,直接查数据库
- 2、如果一级缓存关闭,即使二级缓存开启也没有数据,因为二级缓存的数据从一级缓存获取
- 3、一般不会关闭一级缓存
- 4、如果二级缓存关闭,直接判断一级缓存是否有数据,如果没有就查数据库
- 5、如果二级缓存开启,先判断二级缓存有没有数据,如果有就直接返回;如果没有,就查询一级缓存,如果有就返回,没有就查询数据库;
总结:先查二级缓存,再查一级缓存,再查数据库;即使在一个sqlSession中,也会先查二级缓存;一个namespace中的查询更是如此;
一级缓存工作原理:
图解:
操作过程:
- 第一次发起查询sql查询用户id为1的用户,先去找缓存中是否有id为1的用户,如果没有,再去数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。
- 如果sqlsession执行了commit操作(插入,更新,删除),会清空sqlsession中的一级缓存,避免脏读
- 第二次发起查询id为1的用户,缓存中如果找到了,直接从缓存中获取用户信息
- mybatis默认支持一级缓存。
总结
- 在同一个 SqlSession 中, Mybatis 会把执行的方法和参数通过算法生成缓存的键值, 将键值和结果存放在一个 Map 中, 如果后续的键值一样, 则直接从 Map 中获取数据;
- 不同的 SqlSession 之间的缓存是相互隔离的;
- 用一个 SqlSession, 可以通过配置使得在查询前清空缓存;
- 任何的 UPDATE, INSERT, DELETE 语句都会清空缓存。
二级缓存实现原理
图解:
首先要手动开启mybatis二级缓存。
在config.xml设置二级缓存开关 , 还要在具体的mapper.xml开启二级缓存
<settings>
<!--开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
2.需要将映射的javapojo类实现序列化
class Student implements Serializable{}
3.<!--开启本Mapper的namespace下的二级缓存-->
<cache eviction="LRU" flushInterval="10000"/>
cache属性的简介:
eviction:代表的是缓存回收策略,目前MyBatis提供以下策略。
(1) LRU(Least Recently Used),最近最少使用的,最长时间不用的对象
(2) FIFO(First In First Out),先进先出,按对象进入缓存的顺序来移除他们
(3) SOFT,软引用,移除基于垃圾回收器状态和软引用规则的对象
(4) WEAK,弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。这里采用的是LRU,
移除最长时间不用的对形象
flushInterval:刷新间隔时间,单位为毫秒,这里配置的是100秒刷新,如果你不配置它,那么当
SQL被执行的时候才会去刷新缓存。
size:引用数目,一个正整数,代表缓存最多可以存储多少个对象,不宜设置过大。设置过大会导致内存溢出。
这里配置的是1024个对象
readOnly:只读,意味着缓存数据只能读取而不能修改,这样设置的好处是我们可以快速读取缓存,缺点是我们没有
办法修改缓存,他的默认值是false,不允许我们修改
操作过程:
sqlsession1查询用户id为1的信息,查询到之后,会将查询数据存储到二级缓存中。
如果sqlsession3去执行相同mapper下sql,执行commit提交,会清空该mapper下的二级缓存区域的数据
sqlsession2查询用户id为1的信息, 去缓存找 是否存在缓存,如果存在直接从缓存中取数据
禁用二级缓存:
在statement中可以设置useCache=false,禁用当前select语句的二级缓存,默认情况为true
<select id="getStudentById" parameterType="java.lang.Integer" resultType="Student" useCache="false">
在实际开发中,针对每次查询都需要最新的数据sql,要设置为useCache="false" ,禁用二级缓存
flushCache标签:刷新缓存(清空缓存)
<select id="getStudentById" parameterType="java.lang.Integer" resultType="Student" flushCache="true">
一般下执行完commit操作都需要刷新缓存,flushCache="true 表示刷新缓存,可以避免脏读
二级缓存应用场景
对于访问多的查询请求并且用户对查询结果实时性要求不高的情况下,可采用mybatis二级缓存,降低数据库访问量,提高访问速度,如电话账单查询
根据需求设置相应的flushInterval:刷新间隔时间,比如三十分钟,24小时等。。
注意事项
- 由于在更新时会刷新缓存, 因此需要注意使用场合:查询频率很高, 更新频率很低时使用, 即经常使用 select, 相对较少使用delete, insert, update。
- 缓存是以 namespace 为单位的,不同 namespace 下的操作互不影响。但刷新缓存是刷新整个 namespace 的缓存, 也就是你 update 了一个, 则整个缓存都刷新了。
- 最好在 「只有单表操作」 的表的 namespace 使用缓存, 而且对该表的操作都在这个 namespace 中。 否则可能会出现数据不一致的情况。