当前位置: 首页 > news >正文

MyBatis 延迟加载使用及原理 - Higurashi

一、延迟加载是什么?

延迟加载(Lazy Loading)又称“惰性加载”,指的是:

当查询一个对象时,不立即加载它的关联对象(如一对多、多对一关系),而是在第一次真正使用该关联对象时才去执行 SQL 查询加载它。

举个例子:

User user = userMapper.selectById(1);
// 此时只查了 user 表,不查 order 表
user.getOrders(); // 这一步才去执行查询 orders 的 SQL

这样可以避免一次性加载大量无关数据,提高查询性能。

二、如何开启延迟加载?

在 MyBatis 的mybatis-config.xml中配置:

<settings><!-- 全局启用延迟加载 --><setting name="lazyLoadingEnabled" value="true"/><!-- 设置为 true 时,所有关联对象都会延迟加载 --><setting name="aggressiveLazyLoading" value="false"/>
</settings>

aggressiveLazyLoading:

  • true(旧版本默认):访问任意属性时会触发所有懒加载属性;
  • false:只在访问对应属性时才加载(推荐,性能更好)。

然后在映射文件中配置关联关系:

<resultMap id="userMap" type="User"><id property="id" column="id"/><result property="name" column="name"/><collection property="orders"select="selectOrdersByUserId"column="id"/>
</resultMap>

此时,当访问user.getOrders()时,才会触发对Order的查询。

lazyLoadingEnabled配置是全局开关,也可以在单个映射关系上通过属性fetchType="lazy"来开启懒加载:

<resultMap id="userMap" type="User"><id property="id" column="id"/><result property="name" column="name"/><collection property="orders"fetchType="lazy"select="selectOrdersByUserId"column="id"/>
</resultMap>

三、实现原理(源码层面)

延迟加载的核心为动态代理机制。

查询阶段:创建代理对象

MyBatis 在查询阶段会扫描每个ResultMap的映射字段,判断哪些字段需要懒加载,然后为结果对象创建代理。

DefaultResultSetHandler.handleResultSets()里,MyBatis 读取 ResultSet 时会调用getRowValue()

image-20251014223608719

这个方法会为每一行创建 Java 对象(例如User),并填充属性。注意其中的createResultObject方法和applyPropertyMappings方法,createResultObject创建了结果对象的动态代理对象:

image-20251014223948757
image-20251014224044696
image-20251014224109591

注意createResultObject方法接收lazyLoader作为参数,此时lazyLoader内部是个空集合。

下一步applyPropertyMappings方法才在lazyLoader中添加用于加载不同属性(可能有多个关联属性)的ResultLoader

image-20251015000829613
image-20251015000855780
image-20251015001014696

这样返回的user实际上是一个代理对象,它的某些属性还没被真正赋值。

访问阶段:触发加载

当我们在 Java 代码中第一次调用:

user.getOrders();

其方法被代理,代理逻辑封装在EnhancedResultObjectProxyImpl,其intercept方法中,使用ResultLoaderMap lazyLoader加载了 Getter 方法所获取的属性:

image-20251014235416401

ResultLoaderMap#load最终通过ResultLoader#loadResult加载属性值:

image-20251014235619013
image-20251014235641346
image-20251014235804055

ResultLoader#loadResult通过Executor查询到结果:

image-20251015000204849

这样,数据就在真正访问时被加载。

http://www.hskmm.com/?act=detail&tid=31247

相关文章:

  • ADC-过零检测详解
  • 今日小雨
  • 内网穿透进阶:让 frpc 只代理「真正在线」的端口
  • 规则逻辑与人文逻辑的统一:AI元人文构想的演进之路
  • 2023 ICPC Jinan
  • 二叉树中和为目标值的路径
  • 动态库的调用方式
  • 校招面试官揭秘:我们到底在寻找什么样的技术人才?
  • day011
  • nginx
  • 打造一个比人类更懂 Python 的 AI 编程助手
  • 【黑马python】基础 5.Python 函数:参数 返回值 嵌套
  • linux 命令
  • 一试模拟试题(十七)problem 7 另(数竞相关)
  • PaddleOCR源码安装+centos7.6+python3.10
  • 以后尽量多更新
  • 10/14
  • 算法模版
  • newDay10
  • C#/.NET/.NET Core技术前沿周刊 | 第 57 期(2025年10.1-10.12)
  • Cheap Context and Expensive Context
  • [Mysql]快速执行sql文件
  • Agent之殇
  • 元类编程
  • 1014
  • 10.14日学习笔记
  • python 函数参数的形式以及调用方式
  • SpringBoot开发实用篇(热部署 - 配置高级 - 测试 - 数据层解决方案 ) - a
  • 深入探索Next.js中的SSRF漏洞挖掘
  • 工厂方法+抽象工厂设计模式