MyBatis中存在两种缓存机制:一级缓存、二级缓存。
一级缓存指的是MyBatis自带的基于SqlSession的缓存,自动生效,且无法关闭。
当我们创建一个SqlSession并通过它从数据库中查询到一条数据时,这条数据会放在该SqlSession的缓存区中。
如果使用同一个SqlSession再查询一次相同的内容,则直接从缓存区中返回数据。以此降低查数据库的次数。
如果遇到以下四种情况,一级缓存会失效(无法命中):
- 1、查询的内容和结果完全相同,使用的不是同一个SqlSession
- 2、使用的是同一个SqlSession,但是查询的条件不同(查询结果不同)
- 3、同一个SqlSession,但是在两次查询之间执行了DML(增删改操作)
- 4、手动调用clearCache()清理了缓存区
如果一级缓存无法满足我们的需求,则可以使用二级缓存。二级缓存是基于namespace的全局缓存(基于每一个Mapper映射接口)。
每个Mapper二级缓存都有自己的一个缓存区域(底层Map实现),当一级缓存所在的SqlSession被关闭时,数据就会进入到二级缓存中。
二级缓存使用步骤
1、核心文件中开启全局缓存设置
<setting name="cacheEnabled" value="true">
2、在mapper.xml中开启二级缓存
<cache></cache>
3、需要缓存的数据类型需要实现序列化接口
cache配置中的属性
-
eviction 配置缓存回收策略,可选值:
-
LRU (默认)最近最少使用的,移除最长时间不被使用的对象
-
FIFO 先进先出,按照对象进入缓存的顺序移除它们
-
SOFT 软引用,移除基于垃圾回收器状态和软引用规则的对象
强引用:平时使用new关键字创建的对象都是强引用,例如:
Student stu = new Student(); ArrayList list = new ArrayList();
强引用指的是只要有任何引用指向该对象,那么gc一定不会回收它。
生命周期最长,存在感较强。
软引用:如果内存空间不足,gc在开始工作的时候优先会回收软引用类型的对象。
生命周期一般长,存在感一般强。
-
WEAK 弱引用,更积极地移除基于垃圾回收器状态和弱引用规则的对象
生命周期最短。无论当前内存是否够用,只要gc工作就一定会将弱引用对象回收掉。
public static void main(String[] args) { // 软引用对象 Object obj = new Object(); SoftReference soft = new SoftReference(obj); obj = null; // 弱引用对象 Object obj2 = new Object(); WeakReference weak = new WeakReference(obj2); obj2 = null; }
-
-
flushInterval 缓存刷新间隔,单位为毫秒
如果长时间不刷新缓存区,可能会导致缓存区中的数据和数据库中的不一致。
刷新缓存区的意思就是把所有的缓存全部清除,下一次全部重新查询。
-
readOnly 设置是否“只读“,值为true或false
-
如果设为true,则代表向MyBatis表明我们从缓存中取对象仅仅是为了读取属性,而不会修改。
MyBatis则会将缓存中对象的引用直接返回。
注意:缓存中的数据如果被修改,则没有存在的意义。
特点:速度快、不安全
-
如果设为false,则代表向MyBatis表明我们取出对象之后可能会进行修改操作。
为了保证缓存中的原数据不被修改(与数据库真实数据保持一致),MyBatis会将缓存中的对象通过序列化和反序列化技术克隆一份并返回。
特点:速度慢、安全
-
业务主要以查询为主,可以设置readOnly="true"来增加查询的效率。
如果拿到缓存中的对象之后,由于某些业务逻辑的需要,不得不修改它的一些属性值,
则最好将readOnly设为false以确保数据的安全性、准确性。
-
-
size 缓存中最大对象数量,默认值为1024
-
type 指定自定义缓存
-
如果mapper中某条select语句不希望使用缓存,而是强制到数据库中查询数据,则可以添加如下属性:
<select id="findxxxxByxxxxx" useCache="false">
-
默认情况下,每次执行完DML操作之后缓存都会失效,原因是
<insert>
、<delete>
、<update>
三种元素中存在一个默认的属性值用来配置是否刷新缓存。如果不希望DML之后缓存失效,将其设为false即可: -
<delete id="xxxx" flushCache="false">