MyBatis 一级缓存与二级缓存
一、缓存概述
MyBatis 提供两级缓存机制提升查询性能:
-
一级缓存:SqlSession 级别,默认开启
-
二级缓存:Mapper 级别,需手动开启
两者协同工作,形成查询数据优先级:二级缓存 → 一级缓存 → 数据库
二、一级缓存(Local Cache)
1. 核心特性
-
作用域:单个 SqlSession(数据库会话)
-
生命周期:
-
随 SqlSession 创建而创建
-
随 SqlSession 关闭或清空(
clearCache()
)而销毁
-
-
存储位置:内存中的 HashMap(非序列化)
-
默认状态:开启状态,无需配置
2. 工作流程
3. 缓存失效场景
场景 | 原因 |
---|---|
执行增删改操作 | 任何 INSERT/UPDATE/DELETE 操作都会清空当前 SqlSession 的缓存 |
手动清空缓存 | 调用 sqlSession.clearCache() |
查询条件变化 | SQL 语句或参数不同 |
跨 SqlSession | 不同 SqlSession 的缓存相互隔离 |
4. 验证示例
try (SqlSession session = sqlSessionFactory.openSession()) {UserMapper mapper = session.getMapper(UserMapper.class);// 第一次查询(访问数据库)User user1 = mapper.selectById(1); // 第二次查询(从一级缓存获取)User user2 = mapper.selectById(1); System.out.println(user1 == user2); // 输出 true(同一对象)// 更新操作使缓存失效mapper.updateName(1, "NewName");// 第三次查询(再次访问数据库)User user3 = mapper.selectById(1);
}
三、二级缓存(Second Level Cache)
1. 核心特性
-
作用域:Mapper 级别(同一 Mapper 的多个 SqlSession 共享)
-
存储位置:内存/磁盘(可配置第三方缓存如 Redis、Ehcache)
-
开启条件:需在 Mapper XML 中添加
<cache/>
标签 -
序列化要求:实体类必须实现
Serializable
接口
2. 配置方式
(1) 基础配置
<!-- UserMapper.xml -->
<mapper namespace="com.example.UserMapper"><cache /> <!-- 启用二级缓存 -->
</mapper>
(2) 高级参数
<cache eviction="LRU" <!-- 淘汰策略(默认LRU) -->flushInterval="60000" <!-- 自动刷新间隔(毫秒) -->size="1024" <!-- 最大缓存对象数 -->readOnly="true" /> <!-- 是否只读(性能优化) -->
3. 工作流程
4. 缓存同步机制
-
写入时机:SqlSession 提交(
commit()
)或关闭(close()
)时,一级缓存数据才会转存到二级缓存 -
失效条件:
-
执行同 Mapper 的增删改操作
-
手动调用
sqlSession.clearCache()
-
四、两级缓存对比
特性 | 一级缓存 | 二级缓存 |
---|---|---|
作用域 | SqlSession 内部 | Mapper 级别(跨 SqlSession) |
默认状态 | 开启 | 需手动配置 |
存储位置 | 内存(JVM 堆) | 内存/磁盘/第三方存储 |
序列化要求 | 不需要 | 必须实现 Serializable |
共享性 | 线程隔离 | 进程内共享(集群需分布式缓存) |
失效策略 | 自动随 DML 操作失效 | 需配置淘汰策略(LRU/FIFO/SOFT/WEAK) |
性能影响 | 轻量级 | 可能引入网络开销(分布式缓存) |
五、最佳实践与注意事项
-
适用场景
-
一级缓存:短会话操作(如单个请求处理)
-
二级缓存:读多写少的静态数据(如配置表、历史数据)
-
-
避坑指南
-
脏读问题:
-
避免跨 Mapper 关联查询(如
JOIN
查询)使用二级缓存 -
解决方案:在关联 Mapper 中添加
<cache-ref namespace="..."/>
建立缓存引用
-
-
事务提交:
-
二级缓存需在 SqlSession 提交后生效,确保及时调用
commit()
-
-
分布式环境:
-
默认二级缓存不适用于集群,需集成 Redis 等分布式缓存
-
-
-
性能优化
-
设置
flushInterval
控制自动刷新频率 -
使用只读缓存(
readOnly="true"
)提升读取性能 -
对大数据量结果集启用分页,避免缓存溢出
-
六、扩展:集成 Redis 二级缓存
1. 添加依赖
<dependency><groupId>org.mybatis.caches</groupId><artifactId>mybatis-redis</artifactId><version>1.0.0-beta2</version>
</dependency>
2. 配置 Mapper
<mapper namespace="com.example.UserMapper"><cache type="org.mybatis.caches.redis.RedisCache" />
</mapper>
3. 创建 redis.properties
host=localhost
port=6379
password=
database=0
总结
-
一级缓存:SqlSession 级别,自动开启,适用于会话内重复查询
-
二级缓存:Mapper 级别,需手动配置,适合共享读场景
-
关键区别:作用域、共享性、序列化要求和失效策略
-
生产建议:
-
慎用默认二级缓存,优先考虑 Redis 等分布式方案
-
对写频繁的数据关闭二级缓存
-
监控缓存命中率(
Cache Hit Ratio
)持续优化
-
合理使用两级缓存可显著提升系统性能,但需结合业务特点规避脏读和一致性问题。