一、一级缓存(本地缓存,默认开启,无需手动配置)

1. 作用范围

缓存存放在当前 SqlSession 内部,每个 SqlSession 独立一份缓存,不同 SqlSession 之间互不共享。

2. 底层存储

底层是一个 HashMap,key 由「statementId + 分页参数 + SQL 语句 + 查询参数 + 环境 id」拼接组成,value 是查询出来的结果对象。

3. 生效场景

同一个 SqlSession 内,执行完全相同的查询 SQL、相同参数,第二次查询不会访问数据库,直接从本地 Map 拿数据。 示例:

SqlSession session = sqlSessionFactory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
mapper.selectById(1); // 查库,放入一级缓存
mapper.selectById(1); // 同session,直接走缓存

4. 一级缓存失效场景(高频考点)

  1. SqlSession 执行了 insert/update/delete 增删改操作,会清空当前 session 全部一级缓存;
  2. 手动调用 session.clearCache() 手动清空;
  3. 两次查询中间执行了不同的查询语句、不同参数;
  4. 关闭、提交、回滚当前 SqlSession,缓存直接销毁。

5. 缺陷

多线程、多 SqlSession 环境下会出现脏读: SessionA 查询 id=1 存入缓存,SessionB 更新 id=1 并提交,SessionA 再次查询还是读取旧缓存数据,拿不到最新库中数据。

二、二级缓存(全局 Mapper 缓存,默认关闭,需手动开启)

1. 作用范围

作用域是同一个 Mapper(同一个 namespace),多个 SqlSession 共享这一块缓存,生命周期跟随整个应用。

2. 开启步骤

  1. 全局配置开启总开关:<setting name="cacheEnabled" value="true"/>
  2. 在对应 Mapper.xml 中添加 <cache/> 标签开启当前 namespace 二级缓存;
  3. 查询返回的实体类必须实现 Serializable 序列化接口,二级缓存会将对象序列化存入磁盘 / 内存。

3. 执行查询流程(二级缓存优先级)

  1. 执行查询时,先查当前 Mapper 的二级缓存;
  2. 二级缓存无数据,再去当前 SqlSession 一级缓存查找;
  3. 一级缓存也没有,才访问数据库;
  4. 查询结果先存入一级缓存,SqlSession 提交 / 关闭后,数据才会同步到二级缓存。

4. 二级缓存清空时机

当同一个 namespace 下执行 insert/update/delete,会清空该 Mapper 下全部二级缓存,保证数据一致性。

5. 优缺点

优点:跨 SqlSession 共享缓存,大幅减少数据库请求; 缺点:

  1. 跨 Mapper 操作同一张表时无法感知缓存更新,容易脏读; 比如 UserMapper 查用户存入二级缓存,OrderMapper 更新用户表,不会清空 UserMapper 二级缓存;
  2. 必须实现序列化,开发多一步操作;
  3. 多表关联场景不推荐使用。

三、一级缓存 vs 二级缓存核心对比

  1. 作用域 一级:单个 SqlSession;二级:同一个 Mapper 命名空间,全局共享
  2. 默认状态 一级:默认开启;二级:默认关闭,需手动配置
  3. 共享性 一级不共享;二级多会话共享
  4. 数据存储 一级存内存 HashMap,无需序列化;二级需要序列化存储
  5. 清空规则 一级:当前 session 增删改就清;二级:当前 namespace 增删改才清
  6. 脏读风险 一级:多 session 并发更新会脏读;二级:跨 Mapper 修改同表会脏读

四、生产环境使用建议

  1. 一级缓存不用管,默认开启,单会话重复查询天然优化;
  2. 二级缓存线上谨慎使用:
    • 单表简单 CRUD、极少更新的基础字典表可以开启;
    • 多表关联、多 Mapper 操作同一张业务表,直接关闭二级缓存,避免脏数据;
  3. 高并发实时数据场景,不要依赖 MyBatis 二级缓存,推荐使用 Redis 做分布式缓存,可控性更强。

简短总结

一级缓存是 SqlSession 本地缓存,默认开启,同会话重复查询生效,会话内增删改自动清空,多会话存在脏读;二级缓存是 Mapper 级共享缓存,需要手动开启、实体序列化,多 SqlSession 共享,仅当前命名空间更新才清空缓存,跨 Mapper 更新会出现脏读,复杂业务一般不推荐使用二级缓存。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐