【Java 开发日记】我们来说一下 Mybatis 的缓存机制

【Java 开发日记】我们来说一下 Mybatis 的缓存机制

目录

核心概览

一级缓存

1. 作用域

2. 工作机制

3. 示例说明

4. 注意事项

二级缓存

1. 作用域

2. 开启与配置

3. 工作机制

4. 示例说明

5. 注意事项

缓存顺序与总结

使用建议


核心概览

  • 一级缓存:默认开启,作用范围在 同一个 SqlSession 内。
  • 二级缓存:需要手动配置开启,作用范围在 同一个 Mapper 命名空间(即同一个 Mapper 接口)内,可以被多个 SqlSession 共享。

一级缓存

1. 作用域
  • SqlSession 级别:当同一个 SqlSession 执行相同的 SQL 查询时,MyBatis 会优先从缓存中获取数据,而不是直接查询数据库。
  • 它是 默认开启 的,无法关闭,但可以配置其作用范围(SESSIONSTATEMENT)。
2. 工作机制
  1. 第一次执行查询后,查询结果会被存储到 SqlSession 关联的一级缓存中。
  2. 在同一个 SqlSession 中,再次执行 完全相同的 SQL 查询(包括语句和参数)时,会直接返回缓存中的对象,而不会去数据库查询。
  3. 如果 SqlSession 执行了 增(INSERT)、删(DELETE)、改(UPDATE) 操作,或者调用了 commit()close()rollback() 方法,该 SqlSession 的一级缓存会被清空。这是为了防止读取到脏数据。
3. 示例说明
// 假设获取的 SqlSession 和 UserMapper try (SqlSession sqlSession = sqlSessionFactory.openSession()) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 第一次查询,会发送 SQL 到数据库 User user1 = mapper.selectUserById(1L); System.out.println(user1); // 第二次查询,SQL 和参数完全相同,直接从一级缓存返回,不查询数据库 User user2 = mapper.selectUserById(1L); System.out.println(user2); // 判断是否为同一个对象(是,因为从缓存中返回的是同一个对象的引用) System.out.println(user1 == user2); // 输出:true // 执行一个更新操作 mapper.updateUser(user1); // 此时,一级缓存被清空 // 第三次查询,因为缓存被清空,会再次发送 SQL 到数据库 User user3 = mapper.selectUserById(1L); System.out.println(user3 == user1); // 输出:false (虽然是同一条数据,但已是新对象) }
4. 注意事项
  • 对象相同:一级缓存返回的是 同一个对象的引用,因此在同一个 SqlSession 内,你操作的都是同一个 Java 对象。
  • 分布式环境:一级缓存无法在多个应用服务器之间共享,因为它绑定在单个请求的 SqlSession 上。

二级缓存

1. 作用域
  • Mapper 级别 / Namespace 级别:多个 SqlSession 在访问同一个 Mapper 的查询时,可以共享其缓存。
  • 它是 默认关闭 的,需要在全局配置中开启,并在具体的 Mapper XML 中显式配置。
2. 开启与配置

a. 全局配置文件 (mybatis-config.xml)
必须显式设置开启二级缓存(虽然默认是 true,但显式声明是个好习惯)。

<configuration> <settings> <!-- 开启全局二级缓存,默认就是 true,但建议写明 --> <setting name="cacheEnabled" value="true"/> </settings> </configuration>

b. Mapper XML 文件
在需要开启二级缓存的 Mapper.xml 中添加 <cache/> 标签。

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.mapper.UserMapper"> <!-- 开启本 Mapper 的二级缓存 --> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/> <!-- 其他 SQL 定义 --> <select parameterType="long" resultType="User" useCache="true"> SELECT * FROM user WHERE id = #{id} </select> </mapper>
  • <cache/> 标签属性:
    • eviction:缓存回收策略。
      • LRU(默认):最近最少使用。
      • FIFO:先进先出。
      • SOFT:软引用,基于垃圾回收器状态和软引用规则移除。
      • WEAK:弱引用,更积极地移除。
    • flushInterval:缓存刷新间隔(毫秒),默认不清空。
    • size:缓存存放多少元素。
    • readOnly:是否为只读。
      • true:返回相同的缓存对象实例,性能好,但不允许修改。
      • false(默认):通过序列化返回缓存对象的拷贝,安全,性能稍差。
3. 工作机制
  1. 当一个 SqlSession 执行查询后,在关闭或提交时,其查询结果会被存入二级缓存。
  2. 另一个 SqlSession 执行相同的查询时,会先从二级缓存中查找数据。如果找到,则直接返回,否则再去数据库查询。
  3. 任何一个 SqlSession 执行了 增、删、改 操作并 commit() 后,会清空 整个对应 Mapper 的二级缓存,以保证数据一致性。
4. 示例说明
// 第一个 SqlSession try (SqlSession sqlSession1 = sqlSessionFactory.openSession()) { UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class); User user1 = mapper1.selectUserById(1L); // 查询数据库 sqlSession1.close(); // 关闭时,数据存入二级缓存 } // 第二个 SqlSession(与第一个不同) try (SqlSession sqlSession2 = sqlSessionFactory.openSession()) { UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class); // 查询相同的 SQL,直接从二级缓存获取,不查询数据库 User user2 = mapper2.selectUserById(1L); } // 第三个 SqlSession,执行了更新 try (SqlSession sqlSession3 = sqlSessionFactory.openSession()) { UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class); User user = mapper3.selectUserById(1L); user.setName("New Name"); mapper3.updateUser(user); // 执行更新 sqlSession3.commit(); // 提交时,清空 UserMapper 的二级缓存 } // 第四个 SqlSession try (SqlSession sqlSession4 = sqlSessionFactory.openSession()) { UserMapper mapper4 = sqlSession4.getMapper(UserMapper.class); // 因为缓存已被清空,所以会再次查询数据库 User user4 = mapper4.selectUserById(1L); }
5. 注意事项
  • 实体类序列化:如果二级缓存的 readOnly="false",那么对应的实体类必须实现 Serializable 接口。
  • 事务提交:只有在 SqlSession 执行 commit()close() 时,数据才会从一级缓存转存到二级缓存。
  • 缓存粒度:二级缓存是 Mapper 级别的,有时会显得比较粗粒度。可以通过 <cache-ref> 让多个 Mapper 共享一个缓存,但不推荐,容易引起数据混乱。

缓存顺序与总结

当发起一个查询请求时,MyBatis 的缓存查询顺序是:

  1. 先查二级缓存:查看当前 Mapper 的二级缓存中是否有数据。
  2. 再查一级缓存:如果二级缓存没有,再查看当前 SqlSession 的一级缓存中是否有数据。
  3. 最后查数据库:如果两级缓存都没有,才发送 SQL 语句到数据库执行查询。

查询到的数据会 先存入一级缓存,在 SqlSession 关闭或提交时,再转存到二级缓存

特性

一级缓存

二级缓存

作用域

SqlSession

Mapper (Namespace)

默认状态

开启

关闭

是否共享

否,Session 独享

是,跨 Session 共享

清空时机

UPDATE/INSERT/DELETE, commit(), close()

同 Mapper 的 UPDATE/INSERT/DELETE + commit()

使用建议

  • 查询多,修改少的数据适合使用二级缓存,如字典表、配置项。
  • 数据实时性要求高的场景(如交易、订单)应谨慎使用二级缓存,或者设置较短的刷新间隔。
  • 在分布式环境中,默认的二级缓存(基于内存)是无法共享的,需要集成 Redis、Ehcache 等第三方缓存中间件来替代。
  • 理解缓存机制有助于解决一些“诡异”的问题,比如在同一个事务中,先后查询和更新,但由于一级缓存的存在,后续查询可能看不到其他线程的更新。

如果小假的内容对你有帮助,请点赞评论收藏。创作不易,大家的支持就是我坚持下去的动力!

Read more

【OpenClaw:实战部署】5、全平台部署OpenClaw(Win/Mac/Linux/云服务器)——10分钟跑通第一个本地AI智能体

【OpenClaw:实战部署】5、全平台部署OpenClaw(Win/Mac/Linux/云服务器)——10分钟跑通第一个本地AI智能体

【保姆级教程】全平台部署OpenClaw(Win/Mac/Linux/云服务器)——10分钟跑通第一个本地AI智能体 一句话导读:无论你是Windows用户、Mac爱好者,还是Linux开发者,甚至想在云服务器上7×24小时运行AI智能体,本文都能带你用10分钟完成OpenClaw全平台部署,跑通第一个本地AI指令,告别陪聊机器人,真正拥有“动手能力”。 引言:本地部署 vs 云端部署的核心差异 2026年,OpenClaw(原Clawdbot)凭借跨平台适配性、灵活的技能扩展体系,已成为开源AI Agent领域的热门工具,在GitHub下载排行已攀升至第11位。但在开始部署前,我们需要先搞清楚一个问题:到底选择本地部署,还是云端部署? 这两种方案的核心差异体现在三个维度: 云端部署 本地部署 对比维度 隐私安全 成本结构 稳定性 数据完全本地存储 无泄露风险 零服务器费用 仅需硬件投入 依赖本地设备 关机即停止 数据上传至云端 需信任云厂商 按需付费/

【保姆级】无需公网 IP!Windows 本地一键部署 OpenClaw,10 分钟打造你的飞书 AI 数字员工

【保姆级】无需公网 IP!Windows 本地一键部署 OpenClaw,10 分钟打造你的飞书 AI 数字员工

目录 写在前面 OpenClaw 是什么? 蓝耘平台是什么?与 OpenClaw 的关系 步骤一:极速安装,一行命令搞定环境 步骤二:启动向导,初始化配置参数 步骤 三:注入灵魂,获取蓝耘MaaS API Key 步骤四:打通渠道,搭建飞书长连接桥梁 步骤五:引擎点火,启动核心网关服务 步骤六:仪表盘检阅,后台状态可视化 步骤七:实战演练,验证智能交互效果 快速排错提示 写在末尾 写在前面 本文面向:想在 Windows 本地(PowerShell)一键部署 OpenClaw,使用蓝耘MaaS作为大模型,并通过飞书长连接模式实现 AI 机器人的用户。 内容涵盖:从零开始安装配置、对接飞书机器人、验证与排错的完整流程,

人工智能:自然语言处理在客户服务领域的应用与实战

人工智能:自然语言处理在客户服务领域的应用与实战

人工智能:自然语言处理在客户服务领域的应用与实战 学习目标 💡 理解自然语言处理(NLP)在客户服务领域的应用场景和重要性 💡 掌握客户服务领域NLP应用的核心技术(如聊天机器人、意图识别、情感分析) 💡 学会使用前沿模型(如BERT、GPT-3)进行客户服务文本分析 💡 理解客户服务领域的特殊挑战(如实时性要求、多语言处理、用户体验) 💡 通过实战项目,开发一个客户服务聊天机器人应用 重点内容 * 客户服务领域NLP应用的主要场景 * 核心技术(聊天机器人、意图识别、情感分析) * 前沿模型(BERT、GPT-3)在客户服务领域的使用 * 客户服务领域的特殊挑战 * 实战项目:客户服务聊天机器人应用开发 一、客户服务领域NLP应用的主要场景 1.1 聊天机器人 1.1.1 聊天机器人的基本概念 聊天机器人是通过自然语言与用户进行交互的程序。在客户服务领域,聊天机器人的主要应用场景包括: * 客户服务:回答客户的问题(如“如何退货”、“商品价格”

OpenCode 安装 oh-my-opencode 插件教程(AI 一键辅助安装版)

OpenCode 安装 oh-my-opencode 插件教程(AI 一键辅助安装版)

最近发现一个很有意思的 OpenCode 插件仓库:oh-my-opencode 项目地址:code-yeongyu/oh-my-opencode: The Best Agent Harness. Meet Sisyphus: The Batteries-Included Agent that codes like you. 它的目标是让 OpenCode 具备更“开箱即用”的体验:通过安装插件增强能力,比如更顺手的指令、工作流、提示词封装等。 这篇文章会用仓库作者推荐的方式来安装:把提示词交给 AI,让 AI 自动完成安装。同时我也会补充关键步骤,避免“只会复制粘贴但不知道发生了什么”。 1. 前置条件 开始前确认你已经具备: * 已安装 OpenCode(没有安装的可参考我的另一篇【ClaudeCode平替(免费)】OpenCode 完整安装与 VSCode 使用指南_