为什么很多公司禁用 MyBatis 二级缓存看完你就不敢乱开了先说结论MyBatis 二级缓存默认并不会生效必须显式配置 。但即使如此很多公司仍然选择禁用它因为缓存一致性问题远比性能问题更难处理。很多人学 MyBatis 的时候都会看到这样一个功能cache/官方文档告诉你开启之后查询结果会缓存下次直接从缓存读取减少数据库压力。听起来是不是很美好但现实却是很多公司的 MyBatis 配置里根本不开二级缓存甚至架构规范明确规定禁止使用 MyBatis 二级缓存为什么既然官方提供了这个功能。为什么大厂反而不用今天我们从源码和实际项目角度聊清楚。一级缓存和二级缓存到底是什么很多人先把这两个概念搞混了。一级缓存作用范围SqlSession例如Useruser1mapper.selectById(1);Useruser2mapper.selectById(1);同一个 SqlSession。只会查询一次数据库第二次直接走缓存。缓存位置BaseExecutor源码protectedPerpetualCachelocalCache;结构SqlSession ↓ localCache ↓ 查询结果一级缓存默认开启而且基本没有风险。二级缓存作用范围Mapper级别例如UserMapper多个 SqlSession 共享。配置cache/开启后SqlSession1 ↓ UserMapper Cache ↑ SqlSession2所有会话共享同一份缓存。问题也从这里开始。二级缓存最大的坑数据不一致假设数据库id1 name张三第一次查询selectById(1)结果进入缓存。缓存id1 name张三此时另一个系统修改数据updateusersetname李四whereid1;数据库李四缓存张三这时候selectById(1)读到的还是张三脏数据出现了。为什么互联网项目特别怕这个假设是用户余额数据库 1000缓存1000扣款后数据库 800缓存1000用户再次查询余额1000直接出事故。所以涉及用户余额库存订单权限这种数据。根本不允许出现缓存脏读。MyBatis 根本不知道谁修改了数据库这是最核心的问题。很多人觉得更新时清缓存不就行了理论上没错实际上做不到。因为系统越来越大后服务A 服务B 服务C都可能操作同一张表。例如订单服务 营销服务 后台管理系统 数据同步程序都能更新数据库。MyBatis 二级缓存只能感知自己执行的更新却不知道别人执行的更新所以缓存很容易失效。集群环境更加危险单机还勉强能玩集群直接出问题。例如服务器A 服务器B 服务器C每台机器自己的JVM 自己的缓存结构A缓存 B缓存 C缓存互相不知道。用户访问请求1 → A缓存张三然后请求2 → B数据库已经变成李四结果A返回张三 B返回李四同一个用户两次查询结果不一样。二级缓存本质是 JVM 本地缓存源码PerpetualCache内部结构privatefinalMapObject,Objectcache;其实就是HashMap没错就是 JVM 内存里的一个 Map所以无法跨机器同步天然不适合集群。事务提交后才写入缓存很多人不知道这个细节。查询完成selectById()并不会立刻进入二级缓存。源码TransactionalCache提交事务sqlSession.commit()才会flushPendingEntries()写入缓存。原因很简单避免事务回滚导致缓存脏数据。看起来很聪明但效率反而下降查询流程查询 ↓ 一级缓存 ↓ 二级缓存 ↓ 数据库每次都要检查缓存、每次都要序列化、每次都要维护缓存状态。如果命中率不高缓存收益 维护成本反而变慢。更致命的问题对象序列化开启二级缓存后实体通常要求implementsSerializable例如publicclassUserimplementsSerializable{}原因缓存对象可能需要序列化否则直接报错很多老项目都踩过这个坑。现在大家都用什么替代答案Redis架构变成应用 ↓ Redis ↓ MySQL优势统一缓存所有机器共享Redis不存在A机器缓存 B机器缓存问题。可以主动失效更新数据updateUser();redis.del(key);立即失效比 MyBatis 二级缓存可靠得多。可以设置过期时间TTL30分钟即使忘记删除也不会长期脏数据。支持分布式Redis 天然支持多节点 集群 哨兵 主从远比本地缓存成熟。那二级缓存还有价值吗有。但适用场景非常少。例如基础配置表省份表 城市表 字典表 菜单配置特点读多写少 几乎不更新这种场景比较适合。单体项目没有集群没有微服务只有一台机器这种情况也能使用。为什么大厂普遍禁用真正原因其实只有一句话缓存失效比缓存命中难一万倍。MyBatis 二级缓存解决的是查询性能带来的却是数据一致性风险而对于互联网系统来说错误的数据 比 慢一点的数据 更可怕所以大多数公司的选择都是一级缓存保留 二级缓存关闭 Redis统一管理缓存总结MyBatis 二级缓存并不是没用而是不适合现代互联网架构。核心问题本地缓存 无法跨服务同步 容易出现脏数据源码核心类PerpetualCacheTransactionalCacheCachingExecutor缓存流程一级缓存(SqlSession) ↓ 二级缓存(Mapper) ↓ 数据库所以你会发现很多公司不是不会用二级缓存而是了解原理之后主动选择关闭。上篇文章《MyBatis 插件为什么这么强大一次看懂拦截器机制》下篇文章《MyBatis 到底解决了什么问题》