1. MyBatis缓存机制深度解析
作为一名长期使用MyBatis进行企业级应用开发的工程师,我深刻体会到缓存机制对系统性能的关键影响。记得在一次电商大促中,正是由于合理配置了MyBatis二级缓存,我们的订单查询接口成功扛住了平时10倍的流量冲击。本文将结合我的实战经验,带你深入理解MyBatis的一二级缓存工作原理、使用场景和避坑指南。
MyBatis的缓存分为一级缓存和二级缓存两个层级,它们像计算机的CPU缓存(L1/L2)一样形成层次结构。一级缓存是SqlSession级别的缓存,默认开启且无法关闭;二级缓存是Mapper级别的缓存,需要显式配置才能启用。理解这两级缓存的差异和使用场景,是优化MyBatis应用性能的基础。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 一级缓存:SqlSession级别的缓存
2.1 SqlSession的本质理解
很多初学者容易将SqlSession与数据库连接(Connection)混淆。实际上,SqlSession更像是一次"数据库对话"的抽象。想象你在银行办理业务:
java复制// 开启一次银行对话(不是建立电话连接)
SqlSession session = sqlSessionFactory.openSession();
try {
// 对话中的多个操作
userService.checkBalance(); // 查询余额
userService.transferMoney(); // 转账操作
session.commit(); // 确认所有操作
} finally {
session.close(); // 结束对话
}
在这个比喻中,Connection相当于电话线路,而SqlSession则是这次通话中发生的完整对话过程。理解这一点对掌握一级缓存至关重要。
2.2 一级缓存的工作机制
一级缓存的行为可以通过以下示例代码清晰展示:
java复制public void demoLevel1Cache() {
SqlSession session = sqlSessionFactory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
// 第一次查询ID为1的用户
User user1 = mapper.selectById(1); // 发送SQL查询数据库
System.out.println(user1);
// 第二次查询相同ID
User user2 = mapper.selectById(1); // 不发送SQL!从一级缓存读取
System.out.println(user2);
// 查询不同ID的用户
User user3 = mapper.selectById(2); // 发送SQL:参数不同,缓存未命中
System.out.println(user3);
// 修改用户数据
user1.setName("新名字");
mapper.updateUser(user1); // 执行UPDATE会清空一级缓存
// 再次查询相同ID
User user4 = mapper.selectById(1); // 发送SQL:缓存已被清空
System.out.println(user4);
session.close();
}
关键提示:一级缓存的清空时机非常重要。任何UPDATE/INSERT/DELETE操作都会清空当前SqlSession的一级缓存,即使这些操作修改的是不同的表数据。
2.3 一级缓存的底层实现
一级缓存的实现出奇简单,核心就是一个ConcurrentHashMap:
java复制public class
