💡 一、前言
在实际开发中,数据库查询往往是最容易成为性能瓶颈的地方。为了提升系统响应速度和减轻数据库压力,缓存机制 成为不可或缺的一部分。
MyBatis 提供了两种级别的缓存支持:
- 一级缓存(本地缓存)
- 二级缓存(全局缓存)
本文将带你深入理解 MyBatis 的一级缓存和二级缓存,并结合 Spring Boot 给出完整的整合示例,帮助你在项目中高效地使用缓存技术。
🛠️ 二、环境准备
1. 添加依赖(pom.xml
)
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis Starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Ehcache(用于二级缓存) -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.11</version>
</dependency>
</dependencies>
2. 数据库配置(application.yml
)
spring:
datasource:
url: jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.demo.model
🧪 三、MyBatis 一级缓存(Session 级别)
✅ 什么是 MyBatis 一级缓存?
MyBatis 的 一级缓存是基于 SqlSession 的本地缓存,默认开启。它只对当前会话有效,当会话关闭或提交后缓存失效。
✅ 使用场景
适合在一个请求内重复查询相同数据的场景,例如:
- 同一个用户信息被多次调用;
- 查询结果不变的数据在一次事务中多次使用;
✅ 示例代码
@Mapper
public interface UserMapper {
User selectById(Integer id);
}
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public void testFirstLevelCache() {
User user1 = userMapper.selectById(1);
User user2 = userMapper.selectById(1); // 第二次查询走一级缓存
System.out.println(user1 == user2); // true
}
}
✅ 缓存失效条件
- SqlSession 关闭;
- 执行增删改操作;
- 手动清空缓存(
sqlSession.clearCache()
);
🧢 四、MyBatis 二级缓存(Mapper 级别)
✅ 什么是 MyBatis 二级缓存?
MyBatis 的 二级缓存是跨 SqlSession 的共享缓存,作用范围是 namespace
,即每个 Mapper 接口拥有独立的缓存空间。
默认情况下,MyBatis 不开启二级缓存,需要手动配置。
✅ 开启步骤
1. 实体类实现 Serializable
接口(必须)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private Integer id;
private String name;
}
2. 在 Mapper XML 文件中添加 <cache>
标签
<mapper namespace="com.example.demo.mapper.UserMapper">
<cache/> <!-- 开启二级缓存 -->
<select id="selectById" resultType="User">
SELECT * FROM users WHERE id = #{id}
</select>
</mapper>
3. 全局配置启用二级缓存(可选)
mybatis:
configuration:
cache-enabled: true
✅ 示例代码
@Test
public void testSecondLevelCache() {
SqlSession session1 = sqlSessionFactory.openSession();
UserMapper mapper1 = session1.getMapper(UserMapper.class);
User user1 = mapper1.selectById(1);
session1.close(); // 关闭第一个会话
SqlSession session2 = sqlSessionFactory.openSession();
UserMapper mapper2 = session2.getMapper(UserMapper.class);
User user2 = mapper2.selectById(1); // 第二次查询走二级缓存
session2.close();
System.out.println(user1 == user2); // false(对象不同,但数据一致)
}
✅ 缓存失效条件
- 增删改操作(自动清除缓存);
- 手动刷新缓存;
- 设置过期时间(需引入第三方缓存如 Ehcache);
🧠 五、MyBatis 二级缓存优化 —— 使用 Ehcache
虽然 MyBatis 自带的二级缓存可以使用,但功能有限,推荐使用 Ehcache 或 Redis 来增强缓存能力。
1. 引入 Ehcache 配置文件(ehcache.xml
)
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="1200"
overflowToDisk="true"
/>
</ehcache>
2. 修改 Mapper XML 文件,指定缓存实现类
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
3. 实体类仍需实现 Serializable
public class User implements Serializable { ... }
🧭 六、进阶技巧与最佳实践
技巧 | 描述 | 适用场景 |
---|---|---|
缓存穿透 | 缓存和数据库都没有的数据攻击 | 使用布隆过滤器 |
缓存击穿 | 某个热点数据缓存失效导致大量请求打到 DB | 设置永不过期 + 异步更新 |
缓存雪崩 | 大量缓存同时失效 | 设置随机过期时间 |
缓存预热 | 提前加载常用数据到缓存中 | 系统启动时初始化 |
🔍 七、常见问题与解决方案
问题 | 描述 | 解决方案 |
---|---|---|
二级缓存不生效 | 未实现 Serializable 接口 | 补充接口实现 |
两次查询返回不同对象 | 二级缓存默认不会复用对象引用 | 无需关注,数据一致即可 |
更新后缓存未失效 | 未执行写操作触发清缓存 | 确保执行 insert / update / delete 操作 |
缓存配置无效 | 未正确配置 Ehcache 路径 | 检查 ehcache.xml 路径及依赖版本 |
📘 八、总结对比表
特性 | 一级缓存 | 二级缓存 |
---|---|---|
作用域 | 单个 SqlSession 内 | Mapper 级别(多个 Session 共享) |
默认状态 | 开启 | 关闭(需手动配置) |
存储类型 | HashMap | 可自定义(如 Ehcache、Redis) |
生命周期 | 与 SqlSession 一致 | 与 Mapper 一致 |
是否序列化 | 不需要 | 必须实现 Serializable |
是否跨会话 | 否 | 是 |
📝 九、结语
掌握 MyBatis 的一级缓存和二级缓存机制,不仅能显著提升系统性能,还能减少数据库访问压力,是构建高并发、高性能 Java 应用的重要技能之一。
无论是做后台管理系统、电商系统还是内容平台,合理使用缓存都是必备技能!
如果你觉得有用,欢迎点赞、收藏、转发给更多需要的朋友!