抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

摘要:本文学习了MyBatis的缓存机制,包括一级缓存和二级缓存的使用和配置。

环境

Windows 10 企业版 LTSC 21H2
MySQL 5.7.40
Java 1.8
Maven 3.6.3
MyBatis 3.5.6

1 概述

MyBatis提供两级缓存机制来提高查询性能:

  • 一级缓存:SqlSession级别的缓存,默认开启。
  • 二级缓存:Mapper级别的缓存,默认关闭,需要手动开启。

MyBatis缓存查找顺序:

  1. 先查找二级缓存。
  2. 再查找一级缓存。
  3. 最后查询数据库。

2 使用

2.1 一级缓存

2.1.1 基本概念

一级缓存是SqlSession级别的缓存,在同一个SqlSession中,相同的查询会被缓存起来,避免重复查询数据库。

使用一级缓存:

java
1
2
3
4
5
6
7
8
9
10
11
12
// 获取SqlSession对象
SqlSession session = factory.openSession(true);
// 获取UserMapper接口
UserMapper mapper = session.getMapper(UserMapper.class);
// 执行第一次查询,会访问数据库
User user1 = mapper.selectUserById(1);
// 执行第二次查询,不访问数据库,从一级缓存中获取
User user2 = mapper.selectUserById(1);
// 两次查询的结果是相同对象
System.out.println(user1 == user2);// true
// 关闭SqlSession对象
session.close();

2.1.2 缓存失效

一级缓存在以下情况下失效:

  • 使用不同的SqlSession查询,因为不同的SqlSession对应不同的一级缓存。
  • 使用同一个SqlSession查询,但是两次查询期间手动清空了缓存。
  • 使用同一个SqlSession查询,但是两次查询条件不同。
  • 使用同一个SqlSession查询,但是两次查询期间执行了增删改操作。
  • 使用同一个SqlSession查询,但是两次查询期间提交了事务。

2.2 二级缓存

2.2.1 基本概念

二级缓存是Mapper级别的缓存,可以被多个SqlSession共享。

二级缓存是在SqlSession提交或者关闭时写入的,写入后才能被其他SqlSession读取,并且使用二级缓存的实体类必须实现Serializable接口。

2.2.2 开启配置

在mybatis-config.xml配置文件中开启二级缓存:

xml
1
2
<!-- 是否允许通过配置控制二级缓存是否开启,默认为true表示允许 -->
<setting name="cacheEnabled" value="true"/>

默认开启,一般无需修改。

2.2.3 配置策略

支持通过XML配置和注解配置两种方式配置缓存策略。

常用属性:

属性名 作用 取值
eviction 缓存策略
  • LRU:最近最少使用,移除最长时间不被使用的对象(默认)
  • FIFO:先进先出,按对象进入缓存的顺序来移除
  • SOFT:软引用,基于垃圾回收器状态和软引用规则移除对象
  • WEAK:弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象
flushInterval 缓存刷新间隔(毫秒) 默认不刷新
size 最多缓存对象数 默认为1024
readOnly 是否只读,只读查询返回引用地址相同的相同对象,读写查询返回引用地址不同的相同对象 默认为false表示读写
2.2.3.1 XML配置

在Mapper映射文件中使用cache标签配置缓存策略。

示例:

xml
1
2
3
4
5
6
7
8
<mapper namespace="com.example.mapper.UserMapper">
<!-- 配置二级缓存 -->
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
<!-- 配置SQL语句 -->
<select id="selectUserById" resultType="com.example.pojo.User">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
2.2.3.2 注解配置

在Mapper接口中使用@CacheNamespace注解配置缓存策略。

示例:

java
1
2
3
4
5
@CacheNamespace(eviction=EvictionType.LRU, flushInterval=60000, size=512, readOnly=true)
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User selectUserById(Integer id);
}

2.2.4 实体类要求

使用二级缓存的实体类必须实现Serializable接口:

java
1
2
3
4
public class User implements Serializable {
private static final long serialVersionUID = 1L;
// ...
}

使用二级缓存:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 获取SqlSession对象
SqlSession session = factory.openSession(true);
// 获取UserMapper接口
UserMapper mapper = session.getMapper(UserMapper.class);
// 执行第一次查询,会访问数据库
User user1 = mapper.selectUserById(1);
// 打印第一次查询结果
System.out.println(user1);
// 提交事务,将结果缓存到二级缓存,一级缓存失效
session.commit();
// 执行第二次查询,不访问数据库,从二级缓存中获取
User user2 = mapper.selectUserById(1);
// 打印第二次查询结果
System.out.println(user2);
// 关闭SqlSession对象
session.close();

2.2.5 清除缓存

示例:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 获取SqlSession对象
SqlSession session = factory.openSession(true);
// 获取UserMapper接口
UserMapper mapper = session.getMapper(UserMapper.class);
// 执行第一次查询,会访问数据库
User user1 = mapper.selectUserById(1);
// 打印第一次查询结果
System.out.println(user1);
// 提交事务,将结果缓存到二级缓存,一级缓存失效
session.commit();
// 手动清除二级缓存
factory.getConfiguration().getCache("com.example.mapper.UserMapper").clear();
// 执行第二次查询,会访问数据库
User user2 = mapper.selectUserById(1);
// 打印第二次查询结果
System.out.println(user2);
// 关闭SqlSession对象
session.close();

2.2.6 禁用缓存

2.2.6.1 XML配置

示例:

xml
1
2
3
4
5
6
7
8
<mapper namespace="com.example.mapper.UserMapper">
<!-- 配置二级缓存 -->
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
<!-- 配置SQL语句 -->
<select id="selectUserById" resultType="com.example.pojo.User" useCache="false">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
2.2.6.2 注解配置

示例:

java
1
2
3
4
5
6
@CacheNamespace(eviction=EvictionType.LRU, flushInterval=60000, size=512, readOnly=true)
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
@Options(useCache = false)
User selectUserById(Integer id);
}

2.2.7 缓存失效

二级缓存在以下情况下失效:

  • 执行了增删改操作。
  • 禁用缓存。
  • 清除缓存。

3 自定义缓存

实现Cache接口:

java
1
2
3
public class DemoCache implements Cache {
// ...
}

配置自定义缓存:

xml
1
2
3
4
<!-- 在Mapper中使用自定义缓存 -->
<mapper namespace="com.example.mapper.UserMapper">
<cache type="com.example.cache.DemoCache"/>
</mapper>

评论