MyBtais的一级缓存和二级缓存原理、使用场景解析

 更新时间:2025年12月10日 09:25:18   作者:SadSunset  
文章总结了MyBatis的一级缓存和二级缓存的工作原理、使用场景和优缺点,文章还提供了一级缓存和二级缓存的对比表,并总结了缓存的使用建议,感兴趣的朋友跟随小编一起看看吧

✅ 一、一级缓存(Local Cache)—— 默认开启,SqlSession 级别

🔹 是什么?

  • 作用域:同一个 SqlSession
  • 生命周期:从 openSession()close()commit()/rollback()
  • 默认开启,无需配置

🔹 工作原理

try (SqlSession session = sqlSessionFactory.openSession()) {
    UserMapper mapper = session.getMapper(UserMapper.class);
    User u1 = mapper.selectById(1); // 发起 SQL 查询
    User u2 = mapper.selectById(1); // 不查数据库!直接返回缓存
    System.out.println(u1 == u2); // true(同一个对象)
}

✅ 第二次查询直接从 SqlSession 内部的 HashMap 中返回,不访问数据库

🔹 什么时候失效?

  • 执行了 INSERT / UPDATE / DELETE(任何写操作)
  • 调用了 session.clearCache()
  • session.commit()session.close()

💡 注意:不同 SqlSession 之间不共享一级缓存。

✅ 二、二级缓存(了解即可)(Second-Level Cache)—— Mapper 级别(跨 SqlSession)

🔹 是什么?

  • 作用域:同一个 Mapper namespace 下的所有 SqlSession
  • 生命周期:应用级(只要不清理,一直存在)
  • 默认关闭,需手动开启

🔹 如何开启?

步骤 1:在 MyBatis 主配置中启用(可选,默认已支持)

<settings>
  <setting name="cacheEnabled" value="true"/> <!-- 默认就是 true -->
</settings>

步骤 2:在 Mapper XML 中声明使用缓存

<mapper namespace="com.example.UserMapper">
  <cache /> <!-- 开启二级缓存 -->
  <select id="selectById" resultType="User" useCache="true">
    SELECT * FROM user WHERE id = #{id}
  </select>
</mapper>

步骤 3:实体类必须实现Serializable

public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    // ...
}

🔹 工作流程

  1. 第一个 SqlSession 查询 selectById(1) → 结果存入二级缓存
  2. 第二个 SqlSession 查询 selectById(1) → 直接从二级缓存读取(不查 DB)
  3. 如果执行了 updateUser()整个 UserMapper 的二级缓存被清空

⚠️ 注意:只要 Mapper 中任意语句执行了写操作,整个 namespace 的缓存都会 flush!

⚠️ 三、大厂为什么不推荐用二级缓存?

虽然 MyBatis 提供了二级缓存,但在高并发、分布式系统中,它问题很多

问题说明
脏读风险多节点部署时,A 节点更新数据,B 节点缓存未失效 → 返回旧数据
粒度太粗按 Mapper 清缓存,无法精确到某条记录
序列化开销对象要序列化/反序列化,影响性能
调试困难缓存导致数据“看起来没更新”,排查成本高

✅ 大厂替代方案:

  • Redis / Caffeine应用级缓存(可控、分布式安全)
  • 在 Service 层手动管理缓存逻辑(如 Spring Cache)
  • 禁用 MyBatis 二级缓存(Spring Boot 默认也不开)

📌 真实情况:在阿里、字节等大厂项目中,从未见过生产环境开启 MyBatis 二级缓存

✅ 四、一级 vs 二级缓存对比表

特性一级缓存二级缓存
作用域单个 SqlSession同一个 Mapper(namespace)
默认开启✅ 是❌ 否
跨 SqlSession❌ 否✅ 是
跨 JVM❌ 否❌ 否(仅单机有效)
需要 Serializable❌ 否✅ 是
大厂使用建议✅ 安全可用禁止使用

✅ 五、总结(背下来)

  • 一级缓存:MyBatis 自带,安全、自动、无需管,但只在单次会话内有效。
  • 二级缓存不要用!用 Redis + 手动缓存控制才是正道。
  • 缓存不是银弹:先优化 SQL 和索引,再考虑缓存。

如果你在面试中被问到二级缓存,一定要说:“了解原理,但生产环境我们用 Redis 替代,避免数据不一致问题。” —— 这才是大厂思维!

到此这篇关于MyBtais的一级缓存和二级缓存原理、使用场景解析的文章就介绍到这了,更多相关mybatis一级缓存和二级缓存内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java 17新特性详细讲解与代码实例

    Java 17新特性详细讲解与代码实例

    这篇文章主要给大家介绍了关于Java 17新特性详细讲解与代码实例的相关资料,Java 17是2021年9月发布的最新版本,其中包含了很多新特性和改进,这些新特性和改进将进一步提高 Java 语言的性能和可用性,需要的朋友可以参考下
    2023-09-09
  • java中的日期和时间比较大小

    java中的日期和时间比较大小

    这篇文章主要介绍了java中的日期和时间比较大小,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • SpringCloud融入Python的实现

    SpringCloud融入Python的实现

    这篇文章主要介绍了SpringCloud融入Python的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • Eclipse配置Tomcat和JDK步骤图解

    Eclipse配置Tomcat和JDK步骤图解

    这篇文章主要内容是Eclipse配置Tomcat和JDK步骤图解,需要的朋友可以参考下
    2015-08-08
  • 深入浅析java中finally的用法

    深入浅析java中finally的用法

    finally自己由关键字finally和后面的finally块组成。这篇文章重点给大家介绍java中finally的用法,需要的朋友参考下吧
    2018-06-06
  • 线程池调用kafka发送消息产生的内存泄漏问题排查解决

    线程池调用kafka发送消息产生的内存泄漏问题排查解决

    这篇文章主要为大家介绍了线程池调用kafka发送消息产生的内存泄漏问题排查解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • MybatisPlus整合Flowable出现的坑及解决

    MybatisPlus整合Flowable出现的坑及解决

    这篇文章主要介绍了MybatisPlus整合Flowable出现的坑及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • SpringBoot使用Netty实现远程调用的示例

    SpringBoot使用Netty实现远程调用的示例

    这篇文章主要介绍了SpringBoot使用Netty实现远程调用的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • java封装类型与基础类型对比示例分析

    java封装类型与基础类型对比示例分析

    这篇文章主要为大家介绍了java封装类型与基础类型对比示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • spring boot使用RabbitMQ实现topic 主题

    spring boot使用RabbitMQ实现topic 主题

    本篇文章主要介绍了spring boot使用RabbitMQ实现topic 主题,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03

最新评论