尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

为什么很多公司禁用 MyBatis 二级缓存?看完你就不敢乱开了

为什么很多公司禁用 MyBatis 二级缓存?看完你就不敢乱开了
📅 发布时间:2026/6/23 22:50:28

为什么很多公司禁用 MyBatis 二级缓存?看完你就不敢乱开了


先说结论:MyBatis 二级缓存默认并不会生效,必须显式配置 。但即使如此,很多公司仍然选择禁用它,因为缓存一致性问题远比性能问题更难处理。
很多人学 MyBatis 的时候都会看到这样一个功能:
<cache/>

官方文档告诉你:

开启之后,查询结果会缓存,下次直接从缓存读取,减少数据库压力。

听起来是不是很美好?但现实却是:很多公司的 MyBatis 配置里根本不开二级缓存,甚至架构规范明确规定:

禁止使用 MyBatis 二级缓存

为什么?既然官方提供了这个功能。为什么大厂反而不用?

今天我们从源码和实际项目角度聊清楚。


一级缓存和二级缓存到底是什么

很多人先把这两个概念搞混了。

一级缓存

作用范围:

SqlSession

例如:

Useruser1=mapper.selectById(1);Useruser2=mapper.selectById(1);

同一个 SqlSession。

只会查询一次数据库,第二次直接走缓存。

缓存位置:

BaseExecutor

源码:

protectedPerpetualCachelocalCache;

结构:

SqlSession ↓ localCache ↓ 查询结果

一级缓存默认开启,而且基本没有风险。


二级缓存

作用范围:

Mapper级别

例如:

UserMapper

多个 SqlSession 共享。

配置:

<cache/>

开启后:

SqlSession1 ↓ UserMapper Cache ↑ SqlSession2

所有会话共享同一份缓存。

问题也从这里开始。


二级缓存最大的坑:数据不一致

假设:

数据库:

id=1 name=张三

第一次查询:

selectById(1)

结果进入缓存。

缓存:

id=1 name=张三

此时另一个系统修改数据:

updateusersetname='李四'whereid=1;

数据库:

李四

缓存:

张三

这时候:

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

内部结构:

privatefinalMap<Object,Object>cache;

其实就是:

HashMap

没错,就是 JVM 内存里的一个 Map,所以:

无法跨机器同步

天然不适合集群。


事务提交后才写入缓存

很多人不知道这个细节。

查询完成:

selectById()

并不会立刻进入二级缓存。

源码:

TransactionalCache

提交事务:

sqlSession.commit()

才会:

flushPendingEntries()

写入缓存。

原因很简单:避免事务回滚导致缓存脏数据。


看起来很聪明,但效率反而下降

查询流程:

查询 ↓ 一级缓存 ↓ 二级缓存 ↓ 数据库

每次都要检查缓存、每次都要序列化、每次都要维护缓存状态。

如果命中率不高:

缓存收益 < 维护成本

反而变慢。


更致命的问题:对象序列化

开启二级缓存后:

实体通常要求:

implementsSerializable

例如:

publicclassUserimplementsSerializable{}

原因:缓存对象可能需要序列化,否则直接报错,很多老项目都踩过这个坑。


现在大家都用什么替代

答案:

Redis

架构变成:

应用 ↓ Redis ↓ MySQL

优势:

统一缓存

所有机器共享:

Redis

不存在:

A机器缓存 B机器缓存

问题。


可以主动失效

更新数据:

updateUser();redis.del(key);

立即失效,比 MyBatis 二级缓存可靠得多。


可以设置过期时间

TTL=30分钟

即使忘记删除,也不会长期脏数据。


支持分布式

Redis 天然支持:

多节点 集群 哨兵 主从

远比本地缓存成熟。


那二级缓存还有价值吗

有。但适用场景非常少。

例如:

基础配置表

省份表 城市表 字典表 菜单配置

特点:

读多写少 几乎不更新

这种场景比较适合。


单体项目

没有集群,没有微服务,只有一台机器,这种情况也能使用。


为什么大厂普遍禁用

真正原因其实只有一句话:

缓存失效比缓存命中难一万倍。

MyBatis 二级缓存:

解决的是:

查询性能

带来的却是:

数据一致性风险

而对于互联网系统来说:

错误的数据 比 慢一点的数据 更可怕

所以大多数公司的选择都是:

一级缓存保留 二级缓存关闭 Redis统一管理缓存

总结

MyBatis 二级缓存并不是没用,而是不适合现代互联网架构。

核心问题:

本地缓存 无法跨服务同步 容易出现脏数据

源码核心类:

PerpetualCacheTransactionalCacheCachingExecutor

缓存流程:

一级缓存(SqlSession) ↓ 二级缓存(Mapper) ↓ 数据库

所以你会发现:很多公司不是不会用二级缓存,而是了解原理之后,主动选择关闭。


上篇文章:

《MyBatis 插件为什么这么强大?一次看懂拦截器机制》

下篇文章:

《MyBatis 到底解决了什么问题?》

相关新闻

  • 从 Receiver Agreement 看懂 SAP PI/PO 出站路由的最后一公里
  • Python 3正则表达式完全指南:从入门到精通
  • 微分几何中的等参超曲面与焦点流形稳定性分析

最新新闻

  • dset:革命性微型工具库,197B解决JavaScript深层对象赋值难题 [特殊字符]
  • Clock8性能优化:PHP时间操作的最佳实践与性能对比
  • 3分钟掌握PowerToys:微软官方生产力工具箱的深度解析
  • 如何通过构建核心技术项目实现编程技能突破
  • 使用自动化脚本一般可以实现哪些任务?
  • Dorks Eye完整用户指南:从基础搜索到高级技巧的完整教学

日新闻

  • 终极指南:如何用shadPS4在电脑上免费畅玩PS4游戏
  • 打造个性化Instagram Clone:主题定制与用户体验优化技巧
  • 未来展望:RoseTTAFold-All-Atom的发展路线图与社区支持资源汇总

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号