mybatis一级缓存默认开启、sqlsession级,增删改即清空;二级缓存需手动开启且满足全局开关、mapper中配置、实体类实现serializable三个条件,查数据优先级为二级→一级→数据库。

MyBatis 的一级缓存默认就开着,不用配;二级缓存得手动开,而且要满足三个硬性条件才能真正起作用。用对了能明显减少数据库查询,但配错容易导致查到旧数据——尤其在多用户、高并发或关联查询场景下。
一级缓存:SqlSession 级别的“随身小本子”
它绑定在每次打开的 SqlSession 上,就像你开会时随手记的笔记,关会就清空。同一个 SqlSession 里重复执行完全一样的 select(SQL、参数、分页、环境 ID 全一致),第二次直接从内存 HashMap 拿结果,不碰数据库。
- 增删改操作(哪怕只改了另一张表)会立刻清空当前 SqlSession 的一级缓存,防止脏读
- 调用 sqlSession.clearCache()、commit()、rollback() 或关闭 SqlSession,都会让缓存失效
- Spring Boot 中,没加 @Transactional 时,每个 Service 方法通常对应一个独立 SqlSession;加了事务后,整个事务共用一个 SqlSession —— 这时一级缓存才可能跨多个 Mapper 调用生效
- 注意别误用:不同线程或不同请求的 SqlSession 缓存互不共享,不能靠它做跨请求数据复用
二级缓存:Mapper 级别的“公共资料柜”
它按 Mapper 的 namespace 划分,同一 namespace 下所有 SqlSession 都能读写这个缓存,适合缓存商品分类、地区字典这类读多写少的静态数据。
-
全局开关要打开:Spring Boot 项目在 application.yml 中加:
mybatis:
configuration:
cache-enabled: true -
Mapper XML 里声明
:放在 标签下,可选配参数如: - 实体类必须实现 Serializable 接口:因为二级缓存默认走序列化存储(即使是本地 PerpetualCache),否则启动报错
关键避坑点:别让缓存变成“数据陷阱”
二级缓存看似简单,实际一致性风险很高:
- ProductMapper 执行 update,只会清 ProductMapper 的缓存,不会影响 OrderMapper 里查出的 product 数据 —— 关联查询建议统一用
或干脆禁用二级缓存 - readOnly="false" 表示返回对象拷贝,但深拷贝依赖序列化,若实体含非序列化字段或循环引用,可能失败或卡顿;生产环境推荐设为 true,返回只读对象,性能更稳
- 余额、库存、订单状态等实时性要求高的数据,千万别进二级缓存;应走数据库直查,或用 Redis 做分布式缓存 + 主动失效机制
缓存查询优先级与真实效果
MyBatis 查数据时顺序是:二级缓存 → 一级缓存 → 数据库。一级缓存命中快但范围窄;二级缓存跨会话但有同步延迟(只在 commit/close 后才写入),且写操作仅清理本 namespace 缓存。
- 高频低频数据分开处理:首页 banner、配置项走二级缓存;用户个人订单走一级缓存或不缓存
- 开启后务必压测验证:重点看并发更新+查询是否出现脏数据,尤其是多表 join 场景
- 缓存不是万能药:如果数据修改频繁、查询条件千变万化、或单次查询本身很快(如主键查),开缓存反而增加序列化和判断开销
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











