一、延迟加载是什么?
延迟加载(Lazy Loading)又称“惰性加载”,指的是:
当查询一个对象时,不立即加载它的关联对象(如一对多、多对一关系),而是在第一次真正使用该关联对象时才去执行 SQL 查询加载它。
举个例子:
User user = userMapper.selectById(1);
// 此时只查了 user 表,不查 order 表
user.getOrders(); // 这一步才去执行查询 orders 的 SQL
这样可以避免一次性加载大量无关数据,提高查询性能。
二、如何开启延迟加载?
在 MyBatis 的mybatis-config.xml中配置:
aggressiveLazyLoading:
true(旧版本默认):访问任意属性时会触发所有懒加载属性;
false:只在访问对应属性时才加载(推荐,性能更好)。
然后在映射文件中配置关联关系:
select="selectOrdersByUserId" column="id"/> 此时,当访问user.getOrders()时,才会触发对Order的查询。 lazyLoadingEnabled配置是全局开关,也可以在单个映射关系上通过属性fetchType="lazy"来开启懒加载: fetchType="lazy" select="selectOrdersByUserId" column="id"/> 三、实现原理(源码层面) 延迟加载的核心为动态代理机制。 查询阶段:创建代理对象 MyBatis 在查询阶段会扫描每个ResultMap的映射字段,判断哪些字段需要懒加载,然后为结果对象创建代理。 在DefaultResultSetHandler.handleResultSets()里,MyBatis 读取 ResultSet 时会调用getRowValue(): 这个方法会为每一行创建 Java 对象(例如User),并填充属性。注意其中的createResultObject方法和applyPropertyMappings方法,createResultObject创建了结果对象的动态代理对象: 注意createResultObject方法接收lazyLoader作为参数,此时lazyLoader内部是个空集合。 下一步applyPropertyMappings方法才在lazyLoader中添加用于加载不同属性(可能有多个关联属性)的ResultLoader: 这样返回的user实际上是一个代理对象,它的某些属性还没被真正赋值。 访问阶段:触发加载 当我们在 Java 代码中第一次调用: user.getOrders(); 其方法被代理,代理逻辑封装在EnhancedResultObjectProxyImpl,其intercept方法中,使用ResultLoaderMap lazyLoader加载了 Getter 方法所获取的属性: ResultLoaderMap#load最终通过ResultLoader#loadResult加载属性值: ResultLoader#loadResult通过Executor查询到结果: 这样,数据就在真正访问时被加载。