Mybatis的一级缓存和二级缓存
[参考文献] : https://www.cnblogs.com/happyflyingpig/p/7739749.html
一级缓存
Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存。
在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL。因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。
一级缓存的生命周期
-
MyBatis在开启一个数据库会话时,会创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象。Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。
-
如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用。
-
如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用。
-
SqlSession中执行了任何一个update操作(
update()
、delete()
、insert()
) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用
简单来说
一级缓存生命周期是一个SqlSession,任何通过该SqlSession的更新操作,或主动调用清除缓存,都会清除缓存。
二级缓存
二级缓存默认是不开启的,作用于同一个Mapper下同一个namespace,可以自行配置开启,并实现缓存的存取(接入redis等)。
二级缓存的开启
- MyBatis要求返回的POJO必须是可序列化的(实现Serializable,并且写uid);
- mybatis-config.xml添加开启二级缓存的语句
<configuration>
<settings>
<setting name="cacheEnabled" value="true" />
</settings>
</configuration>
- 在映射XML文件(Mapper文件)配置二级缓存使用
<mapper namespace="com.yihaomen.mybatis.dao.StudentMapper">
<!--
eviction: 缓存回收策略,目前MyBatis提供以下策略。
(1) LRU,最近最少使用的,移除最长时间不用的对象
(2) FIFO,先进先出,按对象进入缓存的顺序来移除他们
(3) SOFT,软引用,移除基于垃圾回收器状态和软引用规则的对象
(4) WEAK,弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。
flushInterval: 刷新间隔时间(毫秒),这里配置的是30秒刷新,如果你不配置它,那么当SQL被执行的时候才会去刷新缓存。
size: 缓存对象个数,不宜设置过大。设置过大会导致内存溢出。
readOnly: 缓存是否只读。
type: 自实现org.apache.ibatis.cache.Cache子类,可接入redis
-->
<cache eviction="LRU" flushInterval="30000" size="1024" readOnly="true" type="path.to.your.cache.implementation"/>
<!--通过useCache设置来开启缓存-->
<select id="listAll" useCache="true">
SELECT * FROM student
</select>
<!-- 刷新二级缓存 -->
<delete id="deleteById" flushCache="true">
DELETE FROM student WHERE id = #{id}
</delete>
</mapper>
- 编写
org.apache.ibatis.cache.Cache
缓存实现子类,以下是该接口源码,可自行实现接入 redis
package org.apache.ibatis.cache;
import java.util.concurrent.locks.ReadWriteLock;
/**
* 参考实现代码:https://blog.csdn.net/xushiyu1996818/article/details/89215428
**/
public interface Cache {
/**![](https://faxjiangyi.github.io/post-images/1699328231064.png)
* 缓存ID
**/
public abstract String getId();
/**
* 写入缓存
**/
public abstract void putObject(Object key, Object value);
/**
* 获取缓存
**/
public abstract Object getObject(Object key);
/**
* key删除缓存
**/
public abstract Object removeObject(Object key);
/**
* 清除所有缓存
**/
public abstract void clear();
/**
* 缓存大小
**/
public abstract int getSize();
/**
* 获取锁
**/
public abstract ReadWriteLock getReadWriteLock();
}