MyBatis一级缓存是SqlSession级私有缓存,默认开启,同会话内重复查询直接返回缓存,执行DML即清空;二级缓存是Mapper级共享缓存,需手动配置,commit后写入,DML操作清空对应namespace全部缓存。

MyBatis 一级缓存和二级缓存,是它内置的两层本地缓存机制,核心目标很实在:减少重复 SQL 查询、降低数据库压力、提升读取性能。它们不是可有可无的附加功能,而是影响数据一致性与系统行为的关键设计点,用对了提效,用错了容易出脏数据。
一级缓存:SqlSession 级别的“私有小本本”
一级缓存默认开启,无需配置,作用域严格限定在**同一个 SqlSession 实例内**。它底层是一个 PerpetualCache(本质是 HashMap),由 SqlSession 内部的 Executor 持有。
- 同一次 SqlSession 中执行两次完全相同的查询(SQL + 参数 + 环境一致),第一次查库并写入缓存,第二次直接返回缓存结果
- 只要在该 SqlSession 中执行过任意 insert/update/delete 操作,不管是否 commit,整个一级缓存都会被清空
- 不同 SqlSession 之间互不共享,哪怕查的是同一张表、同一个 ID,也各自维护独立缓存
- 常见陷阱:事务未提交时,另一个线程用新 SqlSession 查询,看到的仍是旧数据——因为一级缓存不跨会话,也不感知外部变更
二级缓存:Mapper 级别的“公共公告栏”
二级缓存作用域是 **Mapper 的 namespace**,多个 SqlSession 可以共享同一份缓存数据,但需要手动开启,且有明确前提条件。
- 必须在 MyBatis 全局配置中启用:
<setting name="cacheEnabled" value="true"></setting> - 必须在对应 Mapper XML 文件中添加
<cache></cache>或<cache-ref></cache-ref> - 所查实体类必须实现
Serializable接口(因缓存需序列化存储) - 只有在 SqlSession 调用
close()或commit()后,查询结果才会真正写入二级缓存;未提交的查询不参与二级缓存写入 - 同 namespace 下任意增删改操作,会清空该 namespace 对应的整个二级缓存区域
缓存查询顺序与失效逻辑
当一个查询发起时,MyBatis 的实际查找路径是:先查二级缓存 → 再查一级缓存 → 最后查数据库。写入则相反:结果先存一级缓存,commit/close 后再同步到二级缓存。
标签: redis app session 状态码 作用域 red
还木有评论哦,快来抢沙发吧~