[参考文献] : https://www.cnblogs.com/happyflyingpig/p/7739749.html

一级缓存

​ Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存

​ 在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL。因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。

一级缓存的生命周期

  1. MyBatis在开启一个数据库会话时,会创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象。Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。

  2. 如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用。

  3. 如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用。

  4. SqlSession中执行了任何一个update操作(update()delete()insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用

简单来说

​ 一级缓存生命周期是一个SqlSession,任何通过该SqlSession的更新操作,或主动调用清除缓存,都会清除缓存。

二级缓存

二级缓存默认是不开启的,作用于同一个Mapper下同一个namespace,可以自行配置开启,并实现缓存的存取(接入redis等)。

二级缓存的开启

  1. MyBatis要求返回的POJO必须是可序列化的(实现Serializable,并且写uid);
  2. mybatis-config.xml添加开启二级缓存的语句
<configuration>
    <settings>
        <setting name="cacheEnabled" value="true" />
    </settings>
</configuration>
  1. 在映射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>
  1. 编写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();
}