Spring Boot 项目集成 MyBatis 一级缓存与二级缓存完整指南
Spring Boot 项目集成 MyBatis 一级缓存与二级缓存完整指南
在实际开发中,频繁访问数据库会导致性能下降。MyBatis 提供的 两级缓存机制 能够显著减少数据库访问,提高系统性能。本文将详细讲解如何在 Spring Boot 项目中使用 MyBatis 的一级缓存和二级缓存,并展示其使用效果和注意事项。
一、MyBatis 缓存机制概述
MyBatis 内置两级缓存:
- 一级缓存 (Local Cache)
- 范围:SqlSession 级别
- 默认状态:开启,无法关闭
- 生命周期:与 SqlSession 一样,SqlSession 执行 flush/commit/close 时清空
- 特点:同一 SqlSession 内,执行一样的查询 SQL,只访问数据库一次,后续直接从缓存读取
- 二级缓存 (Global Cache)
- 范围:Mapper (Namespace) 级别
- 默认状态:关闭,需要手动开启
- 生命周期:随应用程序存在,多个 SqlSession 可共享
- 特点:当 SqlSession 关闭或提交后,查询结果才会被存入二级缓存,供其他 SqlSession 使用
二、一级缓存(默认开启)
一级缓存无需额外配置,直接使用。
示例
@Mapper
public interface UserMapper {
User selectUserById(Long id);
void updateUserName(Long id, String name);
}
测试:
@SpringBootTest
public class MybatisCacheTest {
@Autowired
private SqlSessionFactory sqlSessionFactory;
@Test
public void testFirstLevelCache() {
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
User u1 = mapper.selectUserById(1L); // 走数据库
User u2 = mapper.selectUserById(1L); // 命中一级缓存,不查库
System.out.println(u1 == u2); // true,同一个对象
}
}
@Test
public void testFirstLevelCacheInvalidation() {
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
mapper.selectUserById(1L);
mapper.updateUserName(1L, "NewName"); // 更新操作清空缓存
mapper.selectUserById(1L); // 再次查库
}
}
}
✅ 总结:
- 一级缓存只在同一 SqlSession 有效
- 增删改操作会清空缓存,避免脏数据
三、二级缓存(手动开启)
1. 开启配置
application.yml
mybatis:
configuration:
cache-enabled: true
Mapper 注解方式:
@Mapper
@CacheNamespace // 启用二级缓存
public interface UserMapper {
User selectUserById(Long id);
}
或 XML 方式:
<mapper namespace="com.example.mapper.UserMapper">
<cache/>
<select id="selectUserById" resultType="User">
select * from user where id = #{id}
</select>
</mapper>
2. 实体类需实现序列化
@Data
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private Integer age;
}
3. 验证二级缓存
@Test
public void testSecondLevelCache() {
try (SqlSession s1 = sqlSessionFactory.openSession();
SqlSession s2 = sqlSessionFactory.openSession()) {
UserMapper m1 = s1.getMapper(UserMapper.class);
UserMapper m2 = s2.getMapper(UserMapper.class);
User u1 = m1.selectUserById(1L); // 查询数据库
s1.close(); // 关闭 session,数据写入二级缓存
User u2 = m2.selectUserById(1L); // 命中二级缓存,不查库
System.out.println(u1 == u2); // false,但数据一样
}
}
✅ 总结:
- 二级缓存数据在 SqlSession commit/close 后才写入
- 增删改会清空对应 Mapper 的二级缓存
四、使用第三方缓存(Ehcache 示例)
MyBatis 自带的二级缓存功能简单,生产中一般用 Ehcache、Redis 等替代。
1. 添加依赖
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.9.2</version>
</dependency>
2. 配置 ehcache.xml
<ehcache updateCheck="false">
<diskStore path="java.io.tmpdir/ehcache"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"/>
<cache name="com.example.mapper.UserMapper"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="false"/>
</ehcache>
3. 修改 Mapper
@Mapper
@CacheNamespace(implementation = org.mybatis.caches.ehcache.EhcacheCache.class)
public interface UserMapper {
User selectUserById(Long id);
}
五、注意事项
- 脏数据风险:多个 Mapper 操作同一表时,缓存同步不必定及时
- 事务性:只有 commit/close 后,二级缓存才生效
- 适用场景:读多写少(字典表、配置表)适合开启二级缓存,写多读少的业务表不提议使用
- 分布式环境:二级缓存最好结合 Redis 等分布式缓存方案
六、一级缓存 vs 二级缓存对比
|
特性 |
一级缓存 |
二级缓存 |
|
作用范围 |
SqlSession 内部 |
Mapper (Namespace) 级别,跨 SqlSession |
|
默认状态 |
开启 |
关闭 |
|
生命周期 |
随 SqlSession 销毁 |
随应用存在 |
|
失效条件 |
增删改 / commit / close |
对应 Mapper 执行增删改 |
|
共享性 |
不能共享 |
可共享 |
七、总结
- 一级缓存:默认开启,无需配置
- 二级缓存:需显式开启,适合读多写少的场景
- 第三方缓存:推荐使用 Ehcache 或 Redis 提升可扩展性

© 版权声明
文章版权归作者所有,未经允许请勿转载。

好棒👏
收藏了,感谢分享