MyBatis-Cache

时间:2023-04-21 15:49:56

一、一级缓存

/**
* 一级缓存(本地缓存):SqlSession 级别。一级缓存是默认开启的,为 SqlSession 级别的一个Map
* 与数据库同一次会话期间查询到的数据会放在本地缓存中,以后如果需要获取相同的数据,直接从缓存中获取。
*/
public static void main(String[] args) throws IOException {
SqlSession session = null;
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
session = sqlSessionFactory.openSession(); MyUserMapper mapper = session.getMapper(MyUserMapper.class);
System.out.println(mapper.selectMyUserById(7));
System.out.println(mapper.selectMyUserById(7));
} finally {
session.close();
}
}

MyBatis-Cache

一级缓存失效的几种情况,相同的查询也会向数据库发送SQL

public static void main(String[] args) throws IOException {
SqlSession session = null;
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
session = sqlSessionFactory.openSession();
MyUserMapper mapper = session.getMapper(MyUserMapper.class); // sqlSession 不同
System.out.println(mapper.selectMyUserById(7));
session = sqlSessionFactory.openSession();
mapper = session.getMapper(MyUserMapper.class);
System.out.println(mapper.selectMyUserById(7)); // sqlSession 相同,查询条件不同(当前一级缓存中还没有这个数据)
System.out.println(mapper.selectMyUserById(7));
System.out.println(mapper.selectMyUserById(8)); // sqlSession 相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
System.out.println(mapper.selectMyUserById(7));
mapper.updateMyUser(new MyUser(10,"xasx",24,null));
System.out.println(mapper.selectMyUserById(7)); // sqlSession 相同,手动清除了一级缓存
System.out.println(mapper.selectMyUserById(7));
session.clearCache();
System.out.println(mapper.selectMyUserById(7));
} finally {
session.close();
}
}

MyBatis-Cache

二、二级缓存

1.开启二级缓存 mybatis-config.xml

<settings>
<!-- 开启全局二级缓存 -->
<setting name="cacheEnabled" value="true"/> <!-- 自动映射有三种模式,NONE、PARTIAL、FULL。NONE 不启用自动映射,PARTIAL 只对非嵌套的 resultMap 进行自动映射,FULL 表示对所有的 resultMap 都进行自动映射。默认为 PARTIAL -->
<setting name="autoMappingBehavior" value="PARTIAL"/>
<!-- 数据库字段下划线转Bean字段的驼峰命名 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 控制台打印SQL -->
<setting name="logImpl" value="STDOUT_LOGGING" /> <!-- 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。默认false -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载。默认false (true in ≤3.4.1) -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>

2.配置二级缓存 xxxMapper.xml

<!-- namespace 对应接口文件的全路径 -->
<mapper namespace="com.dao.MyUserMapper">
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"></cache>
<!-- eviction:缓存的回收策略:默认的是 LRU
• LRU – 最近最少使用的:移除最长时间不被使用的对象。
• FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
• SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
• WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
flushInterval:缓存刷新间隔,缓存多长时间清空一次,默认不清空,设置一个毫秒值
readOnly:缓存中的数据是否只读
true:只读,会将数据在缓存中的引用交给用户。数据可能被修改,不安全,速度快
false:非只读,会利用序列化和反序列的技术克隆一份新的数据返回。安全,速度慢
size:缓存存放多少元素
type:指定自定义缓存的全类名,实现 org.apache.ibatis.cache.Cache 接口 -->
<select id="selectMyUserById" resultType="myUser">
select * from myuser where id = #{id}
</select>

3.实体类实现序列化接口 Serializable

public class MyUser implements Serializable {
private Integer id;
private String name;
private Integer age;
private Dept dept;

4.测试

/**
* 二级缓存(全局缓存):基于 namespace 级别的缓存,一个 namespace 对应一个二级缓存(map)
*
* 创建会话:查询一条数据,这个数据就会被放在当前会话的一级缓存中
* 会话关闭:一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,会先找二级缓存中的内容,没有就找一级缓存,再没有就会发送 SQL 查询数据库
* 效果:数据会从二级缓存中获取,查出的数据都会被默认先放在一级缓存中。只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中
* 使用:
* 1)、在全局配置中开启二级缓存:<setting name="cacheEnabled" value="true"/>
* 2)、在 xxxMapper.xml 中配置二级缓存:<cache/>
* 3)、POJO 实现序列化接口 Serializable
*/
public static void main(String[] args) throws IOException {
SqlSession session = null;
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
session = sqlSessionFactory.openSession(); MyUserMapper mapper = session.getMapper(MyUserMapper.class);
System.out.println(mapper.selectMyUserById(7)); // 关闭 session 让一级缓存中类容提交到二级缓存
session.close(); // 重新获取 sqlSession
session = sqlSessionFactory.openSession();
mapper = session.getMapper(MyUserMapper.class);
System.out.println(mapper.selectMyUserById(7));
} finally {
session.close();
}
}

MyBatis-Cache

三、缓存相关配置

代码配置

// 只清除当前 session 的一级缓存
session.clearCache();

全局设置

<settings>
<!-- 二级缓存设置,不影响一级缓存 -->
<setting name="cacheEnabled" value="false"/>
<!-- 本地(一级)缓存作用域,默认 SESSION,会缓存一个会话(SqlSession)中执行的所有查询。 设置为 STATEMENT,会话仅作用在语句执行上,对 SqlSession 的调用将不会共享数据,可认为是禁用一级缓存 -->
<setting name="localCacheScope" value="SESSION"/>
</settings>

SQL 映射文件配置

<!-- flushCache:将其设置为 true,任何时候只要 SQL 被调用,都会导致本地缓存和二级缓存都会被清空,默认值:true(对应插入、更新和删除语句),false(对应查询语句)。
useCache:将其设置为 true,将会导致本条 SQL 的结果被二级缓存(不影响一级),默认值:对 select 元素为 true -->
<select id="selectMyUserById" resultType="myUser" useCache="true" flushCache="false">
select * from myuser where id = #{id}
</select>

也可以在接口上配置

@Options(flushCache = Options.FlushCachePolicy.FALSE, useCache = true)
public MyUser selectMyUserById(Integer id);

四,使用第三方缓存(二级)

以 ehcache 为例

1.导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com</groupId>
<artifactId>mybatis</artifactId>
<version>1.0-SNAPSHOT</version> <dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.7.0</version>
</dependency>
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.26</version>
</dependency>
</dependencies> <build>
<plugins>
<!-- 指定jdk -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

2.添加缓存配置文件 ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<!-- 磁盘保存路径 -->
<diskStore path="D:\ehcache" /> <!--
diskStore:指定数据在磁盘中的存储位置。
defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略 以下是必须属性:
maxElementsInMemory - 在内存中缓存的element的最大数目
maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上 以下是可选属性:
timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
diskSpoolBufferSizeMB - 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
-->
<defaultCache
maxElementsInMemory="10000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>

3.修改缓存配置,xxxMapper.xml

<!-- namespace 对应接口文件的全路径 -->
<mapper namespace="com.dao.MyUserMapper">
<!-- 引用缓存:namespace:指定和哪个名称空间下的缓存一样 -->
<!--<cache-ref namespace="com.dao.Dept"/>--> <!--使用自定义缓存-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
<select id="selectMyUserById" resultType="myUser" useCache="true" flushCache="false">
select * from myuser where id = #{id}
</select>

5.测试

/**
* 使用第三方缓存:
* 1)、导入依赖;
* 2)、xxxMapper.xml 中使用自定义缓存 <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
*/
public static void main(String[] args) throws IOException {
SqlSession session = null;
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); session = sqlSessionFactory.openSession();
MyUserMapper mapper = session.getMapper(MyUserMapper.class);
System.out.println(mapper.selectMyUserById(7)); session.close(); session = sqlSessionFactory.openSession();
mapper = session.getMapper(MyUserMapper.class);
System.out.println(mapper.selectMyUserById(7));
} finally {
if (session != null) {
session.close();
}
}
}

MyBatis-Cache


http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html#cache

http://www.mybatis.org/ehcache-cache/index.html

相关文章