1. MyBatis缓存机制深度解析
作为Java生态中最受欢迎的ORM框架之一,MyBatis的缓存设计直接影响着应用性能。我在电商系统开发中曾遇到一个典型案例:某商品详情页QPS达到2000+时,数据库负载突然飙升到90%,紧急排查后发现是MyBatis缓存配置不当导致。这个经历让我深刻认识到理解MyBatis缓存机制的重要性。
MyBatis提供了一级缓存(本地缓存)和二级缓存(全局缓存)两级缓存策略,它们像计算机的CPU缓存架构一样分层工作。一级缓存是SqlSession级别的"私人储物柜",而二级缓存则是Mapper级别的"共享仓库"。合理运用这两级缓存,能使数据库查询减少30%-70%,但配置不当也可能导致脏读或内存溢出。接下来我将结合源码和实战案例,拆解这套缓存系统的工作原理和最佳实践。
1.1 一级缓存:SqlSession的私人工作区
默认开启的一级缓存就像开发人员的草稿纸——每个SqlSession拥有自己独立的缓存空间。当执行相同的查询时,MyBatis会优先检查这个"私人储物柜"里是否已有结果。以下是它的核心特征:
- 生命周期:随SqlSession创建而诞生,随SqlSession关闭而销毁
- 存储结构:使用HashMap实现,key由StatementId + Offset + Limit + SQL + Params等要素构成
- 失效场景:
- 执行INSERT/UPDATE/DELETE操作(任何修改都会清空整个缓存)
- 调用sqlSession.clearCache()方法
- 配置flushCache=true的查询语句
java复制// 典型的一级缓存命中场景
try (SqlSession session = sqlSessionFactory.openSession()) {
User user1 = session.selectOne("getUserById", 1); // 查数据库
User user2 = session.selectOne("getUserById", 1); // 命中缓存
System.out.println(user1 == user2); // 输出true,同一对象引用
}
警告:一级缓存可能导致"脏读"。例如在同一个SqlSession中修改数据后立即查询,会读到缓存中的旧值而非数据库最新值。建议在读写分离场景中关闭一级缓存(localCacheScope=STATEMENT)。
1.2 二级缓存:跨SqlSession的共享缓存
二级缓存是Mapper级别的缓存,多个SqlSession可以共享同一份缓存数据。它就像团队共用的文件柜——任何人放入的资料其他成员都能取用。启用二级缓存需要三步:
- 全局配置开启缓存(默认已开启):
xml复制<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
- 在Mapper XML中声明使用缓
