全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-20 8 分钟 ✍️ juanwangdev

二级缓存配置

MyBatis 二级缓存是 Mapper(namespace)级别的缓存,多个 SqlSession 可以共享同一份缓存数据。通过合理配置可以实现跨 Session 的数据共享与缓存管理。

一级与二级缓存对比

特性一级缓存二级缓存
作用域SqlSession 级别Mapper(namespace)级别
共享性不跨 Session多个 Session 共享
默认状态默认开启默认关闭
存储结构PerpetualCache(HashMap)可配置(默认 PerpetualCache)
失效条件写操作后自动清空需手动配置 flushInterval 等
适用场景单 Session 内重复查询多 Session 间数据共享查询

开启二级缓存

1. 全局配置

首先在 mybatis-config.xml 中开启二级缓存支持:

XML
<!-- mybatis-config.xml -->
<settings>
    <!-- 开启二级缓存 -->
    <setting name="cacheEnabled" value="true"/>
</settings>

cacheEnabled 默认值为 true,通常无需修改。设为 false 时将禁用所有二级缓存。

2. Mapper 级别开启

在对应的 Mapper XML 文件中添加 <cache/> 标签:

XML
<!-- UserMapper.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
    
    <!-- 开启二级缓存 -->
    <cache/>
    
    <select id="selectById" resultType="User">
        SELECT * FROM user WHERE id = #{id}
    </select>
    
</mapper>

3. 实体类实现序列化

二级缓存要求缓存的对象实现 Serializable 接口:

Java
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private Long id;
    private String username;
    private String email;
    
    // getters and setters
}

cache 标签属性详解

<cache/> 标签支持多个配置属性:

XML
<cache
    eviction="LRU"
    flushInterval="60000"
    size="1024"
    readOnly="false"
    type="org.apache.ibatis.cache.impl.PerpetualCache"/>
属性默认值说明
evictionLRU缓存回收策略(LRU/FIFO/SOFT/WEAK)
flushInterval缓存刷新间隔(毫秒),不设时只在写操作时刷新
size1024缓存最大存储对象数
readOnlyfalse是否为只读缓存
typePerpetualCache自定义缓存实现类

eviction 回收策略

MyBatis 内置四种缓存回收策略:

策略说明适用场景
LRU最近最少使用(Least Recently Used),淘汰最久未使用的缓存项通用场景,推荐首选
FIFO先进先出(First In First Out),按进入顺序淘汰数据具有时效性
SOFT软引用(Soft Reference),基于 JVM 垃圾回收机制内存敏感,大缓存
WEAK弱引用(Weak Reference),更积极地基于垃圾回收极内存敏感场景

LRU 策略

XML
<!-- 默认策略,可省略 eviction 属性 -->
<cache eviction="LRU" size="512"/>

LRU 算法会记录每个缓存项的使用时间,当缓存满时淘汰最久没有被访问的项。

FIFO 策略

XML
<cache eviction="FIFO" size="512"/>

FIFO 按缓存项进入队列的顺序淘汰,先进入的先被淘汰,不关心是否被访问过。

SOFT / WEAK 引用策略

XML
<cache eviction="SOFT" size="1024"/>

SOFT 和 WEAK 基于 JVM 的引用类型:

  • SOFT:JVM 在内存不足时才回收缓存项
  • WEAK:JVM 在每次 GC 时都可能回收缓存项

flushInterval 刷新间隔

XML
<!-- 每 60 秒自动刷新缓存 -->
<cache flushInterval="60000"/>
配置方式行为
不设置只在 INSERT/UPDATE/DELETE 时刷新缓存
设置毫秒值每隔指定时间自动清空缓存

不设置 flushInterval

XML
<cache/>

缓存只在写操作时刷新,适合读多写少的场景。

设置固定间隔

XML
<!-- 每 30 秒刷新一次 -->
<cache flushInterval="30000" size="256"/>

<!-- 每 5 分钟刷新一次 -->
<cache flushInterval="300000" size="512"/>

flushInterval 设置得越短,缓存命中率越低;设置得越长,数据实时性越差。

size 容量配置

XML
<cache size="1024"/>
场景建议 size说明
小数据量256-512数据表行数少,查询条件单一
中等数据量512-1024通用场景,平衡内存与命中率
大数据量1024-4096查询条件多,缓存项大

size 不是绝对上限,受 eviction 策略影响。LRU/FIFO 会严格限制,SOFT/WEAK 依赖 JVM GC。

readOnly 只读配置

XML
<!-- 只读缓存,返回缓存对象的引用 -->
<cache readOnly="true"/>

<!-- 非只读(默认),返回缓存对象的拷贝 -->
<cache readOnly="false"/>
模式返回值性能安全性
readOnly=true原对象引用高(无拷贝开销)低(可能被修改)
readOnly=false序列化拷贝低(有序列化开销)高(隔离修改)

readOnly 与序列化密切相关,详见下一篇文章《缓存读写策略》。

使用 useCache 和 flushCache 控制缓存

useCache 属性

控制单个 SQL 语句是否使用二级缓存:

XML
<!-- 默认使用二级缓存 -->
<select id="selectById" resultType="User" useCache="true">
    SELECT * FROM user WHERE id = #{id}
</select>

<!-- 不使用二级缓存 -->
<select id="selectById" resultType="User" useCache="false">
    SELECT * FROM user WHERE id = #{id}
</select>
useCache行为适用场景
true(默认)使用二级缓存一般查询
false不使用二级缓存实时查询、统计类 SQL

flushCache 属性

控制 SQL 执行后是否刷新二级缓存:

XML
<!-- 执行后刷新二级缓存 -->
<insert id="insertUser" flushCache="true">
    INSERT INTO user (username, email) VALUES (#{username}, #{email})
</insert>

<select id="selectById" flushCache="true">
    SELECT * FROM user WHERE id = #{id}
</select>
flushCache行为适用场景
true执行后清空二级缓存INSERT/UPDATE/DELETE(默认)
false不清空二级缓存SELECT(默认)

完整配置示例

XML
<!-- UserMapper.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
    
    <!-- 完整二级缓存配置 -->
    <cache
        eviction="LRU"
        flushInterval="60000"
        size="512"
        readOnly="false"/>
    
    <!-- 使用缓存的查询 -->
    <select id="selectById" resultType="User" useCache="true">
        SELECT * FROM user WHERE id = #{id}
    </select>
    
    <!-- 不使用缓存的查询 -->
    <select id="selectRealTime" resultType="User" useCache="false">
        SELECT * FROM user WHERE id = #{id}
    </select>
    
    <!-- 写操作自动刷新缓存 -->
    <update id="updateUser">
        UPDATE user SET username = #{username} WHERE id = #{id}
    </update>
    
</mapper>

二级缓存命中条件

二级缓存的命中条件比一级缓存更严格:

  1. 相同的 Mapper 命名空间namespace 一致
  2. 相同的 SQL 语句MappedStatement.id 一致
  3. 相同的参数值:参数值完全相等
  4. 相同的 RowBounds:分页条件一致
  5. 写操作后未被刷新:INSERT/UPDATE/DELETE 或 flushCache=true
  6. 未超过 flushInterval 间隔:缓存未超时
Java
SqlSessionFactory factory = sqlSessionFactory;

// Session 1
SqlSession session1 = factory.openSession();
UserMapper mapper1 = session1.getMapper(UserMapper.class);
User user1 = mapper1.selectById(1); // 访问数据库,写入二级缓存
session1.commit();
session1.close();

// Session 2(不同 Session)
SqlSession session2 = factory.openSession();
UserMapper mapper2 = session2.getMapper(UserMapper.class);
User user2 = mapper2.selectById(1); // 命中二级缓存
System.out.println(user2);
session2.close();

注意事项

  1. 实体类必须实现 Serializable:二级缓存需要对对象进行序列化
  2. 缓存隔离级别:二级缓存不是线程安全的,多实例环境下可能出问题
  3. 脏读风险:多表关联更新时,只清空当前 Mapper 的缓存可能导致脏数据
  4. flushInterval 与 size:间隔太短导致命中率低,size 太小导致频繁淘汰
  5. 分布式环境:二级缓存是本地缓存,多节点不共享,需使用第三方缓存

要点总结

  • 二级缓存是 Mapper(namespace)级别,多个 SqlSession 共享
  • 开启步骤:全局 cacheEnabled=true → Mapper XML 添加 <cache/> → 实体实现 Serializable
  • 四种 eviction 策略:LRU(推荐)、FIFO、SOFT、WEAK
  • flushInterval 控制自动刷新间隔,size 控制缓存最大容量
  • readOnly 决定返回引用还是拷贝,影响性能与安全性
  • 单条 SQL 可通过 useCache 和 flushCache 精细控制缓存行为
  • 二级缓存不适合分布式环境,多表关联更新可能导致脏数据

存放路径:D:\git2\jwdev\articles\MYBATIS\进阶\缓存机制\二级缓存配置.md

📝 发现内容有误?点击此处直接编辑

← 上一篇 一级缓存机制
下一篇 → 缓存脏数据处理
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库