news 2026/6/16 16:27:51

第9章:MyBatis多级缓存和懒加载

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第9章:MyBatis多级缓存和懒加载

文章目录

  • 第9章:MyBatis多级缓存和懒加载
    • 一级缓存
    • 二级缓存怎么使用
    • 懒加载

第9章:MyBatis多级缓存和懒加载

一级缓存

什么是缓存?

一级缓存核心定位

  • 一级缓存是 MyBatis 内置的默认缓存机制,无需手动配置,默认开启。
  • 作用域:
    • 仅限当前SqlSession(数据库会话)
    • 不同 SqlSession 之间的缓存相互隔离。
  • 缓存介质:
  • 内存(基于HashMap存储),缓存键由Mapper ID + SQL 语句 + 参数 + 分页信息 + 环境信息组成。

核心价值:

  • 减少同一 SqlSession 内重复查询的数据库交互,提升查询性能。

  • 一级缓存生效与失效条件

    场景类型生效条件失效条件
    核心前提同一 SqlSession、相同 Mapper ID+SQL + 参数不同 SqlSession、SQL / 参数 / 分页不同
    数据库操作影响未执行增删改(insert/update/delete)操作执行增删改操作(自动清空当前 SqlSession 缓存)
    手动干预未调用clearCache()close()方法调用sqlSession.clearCache()(手动清空)、sqlSession.close()(关闭会话)
    配置影响默认配置(无特殊禁用)全局配置localCacheScope=STATEMENT(禁用一级缓存)

一级缓存工作流程

一级缓存核心特性:

@Service@Slf4jpublicclassUserService{@AutowiredprivateSqlSessionTemplatesqlSessionTemplate;/*一级缓存 有效的访问*/publicvoidfirstCache(){SqlSessionFactorysqlSessionFactory=sqlSessionTemplate.getSqlSessionFactory();SqlSessionsqlSession=sqlSessionFactory.openSession();UserMapperuserMapper=sqlSession.getMapper(UserMapper.class);Useruser=userMapper.selectById(1);log.info("第一次查询结果:{}",user);Useruser2=userMapper.selectById(1);log.info("第二次查询结果:{}",user2);log.info("两个user是否是同一个对象:{}",user==user2);sqlSession.close();}/*一级缓存 失效的访问*/publicvoidfirstCacheInvalidation(){SqlSessionFactorysqlSessionFactory=sqlSessionTemplate.getSqlSessionFactory();SqlSessionsqlSession=sqlSessionFactory.openSession();UserMapperuserMapper=sqlSession.getMapper(UserMapper.class);Useruser=userMapper.selectById(1);log.info("第一次查询结果:{}",user);/*执行 写的操作*/user.setAge(18);introws=userMapper.update(user);log.info("执行写的操作,影响行数:{}",rows);//清空缓存// sqlSession.clearCache();Useruser2=userMapper.selectById(1);log.info("第二次查询结果:{}",user2);log.info("两个user是否是同一个对象:{}",user==user2);sqlSession.close();}}

二级缓存怎么使用

核心概念界定

二级缓存核心定位

  • 二级缓存(Mapper 级缓存)是 MyBatis 的跨 SqlSession 缓存
    • 作用域为同一个 Mapper(namespace)
    • 不同 SqlSession 可共享缓存数据。
  • 缓存介质:
    • 默认内存(HashMap),支持自定义(如 Redis等第三方缓存)
  • 核心价值:
    • 减少不同 SqlSession 间重复查询的数据库交互
    • 适用于查询频率高、修改频率低的数据(如字典表、配置表)
  • 依赖条件:实体类需实现Serializable接口,需手动开启

一级缓存与二级缓存核心区别

对比维度一级缓存(SqlSession 级)二级缓存(Mapper 级)
作用域单个 SqlSession同一个 Mapper(namespace)
共享性不可跨 SqlSession 共享可跨 SqlSession 共享
开启方式默认开启,无需配置需全局配置 + Mapper 配置手动开启
实体类要求无强制序列化要求必须实现 Serializable 接口
失效触发同一 SqlSession 内增删改、clearCache ()对应 Mapper 内增删改操作、缓存过期等
适用场景单会话内重复查询多会话共享高频查询数据

二级缓存工作流程

二级缓存开启条件(三步缺一不可)

  • 全局配置开启:
    • springBoot 配置文件中设置cacheEnabled=true
  • Mapper 级开启:
    • 在 Mapper XML 中添加<cache/>标签
  • 实体类序列化:
    • 缓存的实体类必须实现java.io.Serializable接口(避免序列化异常)。

二级缓存配置详解

mybatis:configuration:cache-enabled:true# 启用二级缓存
<!-- Mapper XML 中配置二级缓存 --><mappernamespace="com.example.mapper.UserMapper"><!-- 开启二级缓存配置 --><cacheeviction="LRU"flushInterval="60000"size="512"readOnly="true"/><selectid="selectUserById"parameterType="long"resultType="User"useCache="true">SELECT * FROM user WHERE id = #{id}</select></mapper>

二级缓存属性详解表

属性可选值默认值说明
evictionLRU/FIFO/SOFT/WEAKLRU缓存回收策略
flushInterval毫秒数缓存刷新间隔
size正整数1024缓存引用数量
readOnlytrue/falsefalse是否只读
blockingtrue/falsefalse是否使用阻塞缓存

常见的缓存回收策略:

策略缩写全称策略说明
LRULeast Recently Used移除最长时间未被使用的对象(默认策略)。
FIFOFirst In First Out按对象进入缓存的顺序来移除它们。
SOFTSoft Reference基于垃圾回收器状态和软引用规则来移除对象。
WEAKWeak Reference更积极地基于垃圾收集器状态和弱引用规则移除对象。
// 使用二级缓存需要实体类实现Serializable接口@Data@NoArgsConstructor@AllArgsConstructorpublicclassUserimplementsSerializable{privateLongid;privateStringusername;privateStringemail;privateIntegerage;privateDatecreateTime;privateDateupdateTime;// 关联对象也需要序列化}
// 二级缓存服务演示@Service@Slf4jpublicclassSecondLevelCacheService{@AutowiredprivateUserMapperuserMapper;/** * 演示二级缓存跨SqlSession共享 */publicvoiddemonstrateSecondLevelCache(){Useruser1=userMapper.selectUserById(1L);log.info("SqlSession查询: {}",user1);// 重新调用方法模拟第二个SqlSession(实际应用中可能是另一个请求)log.info("=== 二级缓存演示结束 ===");}/** * 二级缓存失效场景 */publicvoiddemonstrateSecondLevelCacheInvalidation(){// 执行更新操作Useruser1=newUser();user1.setId(1L);user1.setEmail("newemail@example.com");intupdateCount=userMapper.updateUser(user1);log.info("更新影响行数: {}",updateCount);}}

懒加载

懒加载核心定位

  • 懒加载(延迟加载)是 MyBatis 关联查询的性能优化机制
    • 指查询主对象时,不立即加载关联对象
    • 而是在首次访问关联对象时才触发查询xa
  • 对立概念:
    • 立即加载(默认行为),查询主对象时同时加载所有关联对象
  • 核心价值:
    • 避免不必要的关联查询,
    • 减少数据库压力
    • 如仅需查询用户基本信息时,无需加载其所有订单
  • 适用场景:
    • 一对一、一对多、多对多关联查询,且关联数据不总是需要使用

懒加载与立即加载对比

懒加载开启条件

  • 全局配置开启延迟加载:
    • lazyLoadingEnabled=true(默认 false)
  • 关闭积极加载:
    • aggressiveLazyLoading=false
    • SpringBoot 2.x+ 已默认关闭,确保按需加载
  • 关联标签配置(可选):
    • associationcollection标签添加fetchType="lazy"(优先级高于全局配置)

懒加载配置详解

mybatis:configuration:lazy-loading-enabled:true# 开启全局懒加载aggressive-lazy-loading:false# 关闭积极加载(按需加载)map-underscore-to-camel-case:true

懒加载实战案例

<!-- 基础用户结果映射(不包含关联对象) --><resultMapid="BaseUserMap"type="com.example.entity.User"><idcolumn="user_id"property="userId"/><resultcolumn="user_name"property="userName"/><resultcolumn="card_id"property="cardId"/></resultMap><!-- 嵌套查询结果映射:使用子查询方式加载关联对象 --><resultMapid="UserWithIdCardNestedQueryMap"type="com.example.entity.User"extends="BaseUserMap"><associationproperty="idCard"column="card_id"select="com.example.mapper.IdCardMapper.selectById"javaType="com.example.entity.IdCard"fetchType="lazy"/></resultMap><!-- 嵌套查询方式:查询用户(触发子查询加载身份证) --><selectid="selectUserWithIdCardNested"resultMap="UserWithIdCardNestedQueryMap">SELECT user_id, user_name, card_id FROM t_user WHERE user_id = #{userId}</select>

懒加载最佳实践

  • 适用场景:

    • 关联数据量大,且不经常使用
    • 需要快速响应的列表查询
    • 移动端应用,减少数据传输
  • 注意事项:
    ) -->

    SELECT
    user_id,
    user_name,
    card_id
    FROM t_user
    WHERE user_id = #{userId}

懒加载最佳实践 - 适用场景: - 关联数据量大,且不经常使用 - 需要快速响应的列表查询 - 移动端应用,减少数据传输 - 注意事项: - 注意 N+1 查询问题
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 18:41:03

C#权威指南第10章:继承

在第9章中学习了面向对象编程的核心概念之一&#xff1a;类。C#是一种面向对象的语言&#xff0c;从本章开始&#xff0c;我们将逐个学习面向对象编程的基本特征&#xff0c;本章要从继承性开始讨论。继承机制可以提高软件模块的可复用性和可扩展性&#xff0c;以提高软件开发效…

作者头像 李华
网站建设 2026/6/13 11:36:26

使用 useAgent 与 LangGraph 构建全栈 AI Agent 应用

AI agent 正在迅速从令人惊叹的演示演进到大规模的生产级应用&#xff0c;而 LangGraph 让这一转变比以往更顺畅。但在此之前&#xff0c;把这些 agent 接到一个 frontend&#xff08;并为用户提供实时交互&#xff09;往往需要一堆杂乱的 API、state management&#xff0c;以…

作者头像 李华
网站建设 2026/6/15 15:52:00

携程闹乌龙,误发通知全员都被离职了。

1月12日晚&#xff0c;大量携程员工突然收到一条措辞正式的离职通知短信&#xff0c;内容以“XX你好&#xff0c;感谢一路相伴”开头。此次乌龙事件源于内部沟通软件trappal下线&#xff0c;在关停关联手机号绑定功能时&#xff0c;工作人员未提前关闭系统预设的短信提醒&#…

作者头像 李华
网站建设 2026/6/13 15:37:27

国产知识管理平台崛起:Gitee Wiki如何领跑企业数字化转型新赛道

国产知识管理平台崛起&#xff1a;Gitee Wiki如何领跑企业数字化转型新赛道 随着"十四五"规划明确提出加快数字化发展步伐&#xff0c;企业知识管理平台正迎来前所未有的战略机遇期。在信创产业蓬勃发展的背景下&#xff0c;国产Wiki系统已从单纯的内容管理工具进化为…

作者头像 李华
网站建设 2026/6/16 6:04:07

RAG性能瓶颈突破:文档切分的核心逻辑与最优实践

引言在检索增强生成&#xff08;RAG&#xff09;系统中&#xff0c;有一个看似基础却能决定系统成败的关键环节——文档切分。很多开发者搭建的RAG系统&#xff0c;检索结果不准确、生成内容驴唇不对马嘴&#xff0c;究其原因&#xff0c;往往是文档切分做得不到位。想象一下&a…

作者头像 李华