源码猎人source-code-hunter:MyBatis延迟加载机制深度解析
引言:性能优化的关键利器
在复杂的业务场景中,我们经常需要处理对象间的关联关系。传统的急切加载(Eager Loading)方式会在查询主对象时立即加载所有关联对象,这在关联数据量大或关联层级深时会造成严重的性能问题。MyBatis的延迟加载(Lazy Loading)机制正是为了解决这一痛点而生,它允许我们在真正需要时才加载关联数据,从而显著提升系统性能。
读完本文,你将掌握:
- MyBatis延迟加载的核心实现原理
- 延迟加载的配置和使用方法
- 底层源码的关键实现细节
- 实际应用中的最佳实践
一、延迟加载机制概述
1.1 什么是延迟加载?
延迟加载(Lazy Loading)是一种数据加载策略,它推迟关联数据的加载时机,直到真正访问这些数据时才执行查询操作。这种机制特别适用于以下场景:
- 一对多/多对多关联关系:避免加载大量不必要的关联数据
- 复杂对象图:减少数据库查询次数,提升响应速度
- 大数据量场景:防止内存溢出和性能瓶颈
1.2 MyBatis延迟加载的实现方式
MyBatis通过动态代理技术实现延迟加载,当访问关联属性时,代理对象会触发实际的数据库查询操作。这种实现方式对业务代码完全透明,开发者无需关心具体的加载时机。
二、核心源码解析
2.1 BaseExecutor中的延迟加载基础设施
在BaseExecutor类中,MyBatis为延迟加载提供了基础支持:
public abstract class BaseExecutor implements Executor {
// 延迟加载队列
protected ConcurrentLinkedQueue<DeferredLoad> deferredLoads;
// 延迟加载方法
@Override
public void deferLoad(MappedStatement ms, MetaObject resultObject,
String property, CacheKey key, Class<?> targetType) {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 创建延迟加载任务并加入队列
DeferredLoad deferredLoad = new DeferredLoad(resultObject, property, key,
targetType, configuration, ms);
deferredLoads.add(deferredLoad);
}
}
2.2 DeferredLoad内部类实现
DeferredLoad是延迟加载的核心实现类,它封装了延迟加载所需的所有信息:
private static class DeferredLoad {
private final MetaObject resultObject;
private final String property;
private final Class<?> targetType;
private final CacheKey key;
private final MappedStatement mappedStatement;
public DeferredLoad(MetaObject resultObject, String property,
CacheKey key, Class<?> targetType,
Configuration configuration, MappedStatement mappedStatement) {
this.resultObject = resultObject;
this.property = property;
this.key = key;
this.targetType = targetType;
this.mappedStatement = mappedStatement;
}
public void load() {
// 实际执行延迟加载的逻辑
try {
final Object value = mappedStatement.getConfiguration()
.getExecutor().query(mappedStatement,
resultObject.getOriginalObject(),
RowBounds.DEFAULT, null, key, null);
resultObject.setValue(property, value);
} catch (SQLException e) {
throw new ExecutorException("Lazy load failed: " + e.getMessage(), e);
}
}
}
2.3 延迟加载的触发时机
在BaseExecutor.query()方法的最后,会检查并执行延迟加载任务:
@Override
public <E> List<E> query(MappedStatement ms, Object parameter,
RowBounds rowBounds, ResultHandler resultHandler,
CacheKey key, BoundSql boundSql) throws SQLException {
// ... 主要查询逻辑
finally {
queryStack--;
}
if (queryStack == 0) {
// 执行所有延迟加载任务
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
deferredLoads.clear();
}
return list;
}
三、配置与使用详解
3.1 全局配置选项
在MyBatis配置文件中,可以通过以下配置启用延迟加载:
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



