您的位置:首页 > 数据库

精尽MyBatis源码分析 - SQL执行过程(四)之延迟加载

2020-11-26 09:19 1016 查看

该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址Mybatis-Spring 源码分析 GitHub 地址Spring-Boot-Starter 源码分析 GitHub 地址)进行阅读

MyBatis 版本:3.5.2

MyBatis-Spring 版本:2.0.3

MyBatis-Spring-Boot-Starter 版本:2.1.4

MyBatis的SQL执行过程

在前面一系列的文档中,我已经分析了 MyBatis 的基础支持层以及整个的初始化过程,此时 MyBatis 已经处于就绪状态了,等待使用者发号施令了

那么接下来我们来看看它执行SQL的整个过程,该过程比较复杂,涉及到二级缓存,将返回结果转换成 Java 对象以及延迟加载等等处理过程,这里将一步一步地进行分析:

MyBatis中SQL执行的整体过程如下图所示:

在 SqlSession 中,会将执行 SQL 的过程交由

Executor
执行器去执行,过程大致如下:

  1. 通过
    DefaultSqlSessionFactory
    创建与数据库交互的
    SqlSession
    “会话”,其内部会创建一个
    Executor
    执行器对象
  2. 然后
    Executor
    执行器通过
    StatementHandler
    创建对应的
    java.sql.Statement
    对象,并通过
    ParameterHandler
    设置参数,然后执行数据库相关操作
  3. 如果是数据库更新操作,则可能需要通过
    KeyGenerator
    先设置自增键,然后返回受影响的行数
  4. 如果是数据库查询操作,则需要将数据库返回的
    ResultSet
    结果集对象包装成
    ResultSetWrapper
    ,然后通过
    DefaultResultSetHandler
    对结果集进行映射,最后返回 Java 对象

上面还涉及到一级缓存二级缓存延迟加载等其他处理过程

SQL执行过程(四)之延迟加载

在前面SQL执行过程一系列的文档中,已经详细地分析了在 MyBatis 的SQL执行过程中,SqlSession 会话将数据库相关操作交由 Executor 执行器去完成,通过 StatementHandler 去执行数据库的操作,并获取到数据库的执行结果,如果是查询结果则通过 DefaultResultSetHandler 对结果集进行映射,转换成 Java 对象

其中 MyBatis 也提供了延迟加载的功能,当调用实体类需要延迟加载的属性的 getter 方法时,才会触发其对应的子查询,获取到查询结果,设置该对象的属性值

在上一篇《SQL执行过程(三)之ResultSetHandler》文档中讲到

  1. 如果存在嵌套子查询且需要延迟加载,则会通过

    ProxyFactory
    动态代理工厂,为返回结果的实例对象创建一个动态代理对象(Javassist),也就是说返回结果实际上是一个动态代理对象

    可以回到上一篇文档的4.2.1createResultObject方法小节第

    4
    步看看

    resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration,
    objectFactory, constructorArgTypes, constructorArgs;
  2. 后续属性映射的过程中,如果该属性是嵌套子查询并且需要延迟加载,则会创建一个

    ResultLoader
    对象添加到上面的
    ResultLoaderMap
    对象
    lazyLoader

    可以回到上一篇文档的4.2.4.2getNestedQueryMappingValue方法小节第

    6
    步看看

    final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery,
    nestedQueryParameterObject, targetType, key, nestedBoundSql);
    if (propertyMapping.isLazy()) { // <6.2> 如果要求延迟加载,则延迟加载
    // <6.2.1> 如果该属性配置了延迟加载,则将其添加到 `ResultLoader.loaderMap` 中,等待真正使用时再执行嵌套查询并得到结果对象
    lazyLoader.addLoader(property, metaResultObject, resultLoader);
    // <6.2.2> 返回延迟加载占位符
    value = DEFERRED;
    } else { // <6.3> 如果不要求延迟加载,则直接执行加载对应的值
    value = resultLoader.loadResult();
    }

那么接下来我们来看看 MyBatis 中的延迟加载是如何实现的

ResultLoader

org.apache.ibatis.executor.loader.ResultLoader
:延迟加载的加载器,在上面你可以看到需要延迟加载的属性会被封装成该对象

构造方法

public class ResultLoader {

/**
* 全局配置对象
*/
protected final Configuration configuration;
/**
* 执行器
*/
protected final Executor executor;
/**
* MappedStatement 查询对象
*/
protected final MappedStatement mappedStatement;
/**
* 查询的参数对象
*/
protected final Object parameterObject;
/**
* 目标的类型,返回结果的 Java Type
*/
protected final Class<?> targetType;
/**
* 实例工厂
*/
protected final ObjectFactory objectFactory;
protected final CacheKey cacheKey;
/**
* SQL 相关信息
*/
protected final BoundSql boundSql;
/**
* 结果抽取器
*/
protected final ResultExtractor resultExtractor;
/**
* 创建 ResultLoader 对象时,所在的线程的 id
*/
protected final long creatorThreadId;
/**
* 是否已经加载
*/
protected boolean loaded;
/**
* 查询的结果对象
*/
protected Object resultObject;

public ResultLoader(Configuration config, Executor executor, MappedStatement mappedStatement,
Object parameterObject, Class<?> targetType, CacheKey cacheKey, BoundSql boundSql) {
this.configuration = config;
this.executor = executor;
this.mappedStatement = mappedStatement;
this.parameterObject = parameterObject;
this.targetType = targetType;
this.objectFactory = configuration.getObjectFactory();
this.cacheKey = cacheKey;
this.boundSql = boundSql;
this.resultExtractor = new ResultExtractor(configuration, objectFactory);
this.creatorThreadId = Thread.currentThread().getId();
}
}

主要包含以下信息:

  • executor
    :执行器
  • mappedStatement
    :查询语句的MappedStatement对象
  • parameterObject
    :子查询的入参
  • targetType
    :返回结果的Java Type
  • boundSql
    :SQL相关信息
  • resultExtractor
    :查询结果的抽取器
  • loaded
    :是否已经加载

loadResult方法

loadResult()
方法,延迟加载的执行器的执行方法,获取到查询结果,并提取出结果,方法如下:

public Object loadResult() throws SQLException {
// <1> 查询结果
List<Object> list = selectList();
// <2> 提取结果
resultObject = resultExtractor.extractObjectFromList(list, targetType);
// <3> 返回结果
return resultObject;
}

selectList方法

selectList()
方法,执行延迟加载对应的子查询,获取到查询结果,方法如下:

private <E> List<E> selectList() throws SQLException {
// <1> 获得 Executor 对象
Executor localExecutor = executor;
if (Thread.currentThread().getId() != this.creatorThreadId || localExecutor.isClosed()) {
// 创建一个的 Executor 对象,保证线程安全
localExecutor = newExecutor();
}
try {
// <2> 执行查询
return localExecutor.query(mappedStatement, parameterObject, RowBounds.DEFAULT,
Executor.NO_RESULT_HANDLER, cacheKey, boundSql);
} finally {
// <3> 关闭 Executor 对象
if (localExecutor != executor) {
localExecutor.close(false);
}
}
}
  1. 获得 Executor 执行器,如果当前线程不是创建 ResultLoader 对象时所在的线程的,或者这个执行器被关闭了,那么需要调用
    newExecutor()
    方法创建一个新的执行器
  2. 通过该执行器进行数据的查询,并返回查询结果
  3. 如果这个执行器是新创建的,则需要关闭它

newExecutor方法

newExecutor()
方法,创建一个新的Executor执行器用于执行延迟加载的子查询,执行完后需要关闭,方法如下:

private Executor newExecutor() {
// 校验 environment
final Environment environment = configuration.getEnvironment();
if (environment == null) {
throw new ExecutorException("ResultLoader could not load lazily.  Environment was not configured.");
}
// 校验 DataSource
final DataSource ds = environment.getDataSource();
if (ds == null) {
throw new ExecutorException("ResultLoader could not load lazily.  DataSource was not configured.");
}
// 创建 Transaction 对象
final TransactionFactory transactionFactory = environment.getTransactionFactory();
final Transaction tx = transactionFactory.newTransaction(ds, null, false);
// 创建 Executor 对象
return configuration.newExecutor(tx, ExecutorType.SIMPLE);
}

ResultExtractor

org.apache.ibatis.executor.ResultExtractor
:结果提取器,用于提取延迟加载对应的子查询的查询结果,转换成Java对象,代码如下:

public class ResultExtractor {
/**
* 全局配置对象
*/
private final Configuration configuration;
/**
* 实例工厂
*/
private final ObjectFactory objectFactory;

public ResultExtractor(Configuration configuration, ObjectFactory objectFactory) {
this.configuration = configuration;
this.objectFactory = objectFactory;
}

/**
* 从 list 中,提取结果
*
* @param list list
* @param targetType 结果类型
* @return 结果
*/
public Object extractObjectFromList(List<Object> list, Class<?> targetType) {
Object value = null;
/*
* 从查询结果中抽取数据转换成目标类型
*/
if (targetType != null && targetType.isAssignableFrom(list.getClass())) { // <1> 场景1,List 类型
// 直接返回
value = list;
} else if (targetType != null && objectFactory.isCollection(targetType)) { // <2> 场景2,集合类型
// <2.1> 创建集合的实例对象
value = objectFactory.create(targetType);
// <2.2> 将结果添加到其中
MetaObject metaObject = configuration.newMetaObject(value);
// <2.3> 将查询结果全部添加到集合对象中
metaObject.addAll(list);
} else if (targetType != null && targetType.isArray()) { // <3> 场景3,数组类型
// <3.1> 获取数组的成员类型
Class<?> arrayComponentType = targetType.getComponentType();
// <3.2> 创建数组对象,并设置大小
Object array = Array.newInstance(arrayComponentType, list.size());
if (arrayComponentType.isPrimitive()) { // <3.3> 如果是基本类型
for (int i = 0; i < list.size(); i++) {
// 一个一个添加到数组中
Array.set(array, i, list.get(i));
}
value = array;
} else {
// <3.4> 将 List 转换成 Array
value = list.toArray((Object[]) array);
}
} else { // <4> 场景4
if (list != null && list.size() > 1) {
throw new ExecutorException("Statement returned more than one row, where no more than one was expected.");
} else if (list != null && list.size() == 1) {
// 取首个结果
value = list.get(0);
}
}
return value;
}
}

List<Object> list
查询结果提取数据,转换成目标类型,有以下四种场景:

  1. List类型,则直接返回

  2. 集合类型,则为该集合类型创建一个实例对象,并把

    list
    全部添加到该对象中,然后返回

  3. 数组类型

    获取数组的成员类型
  4. 创建数组对象,并设置大小
  5. 如果是基本类型则一个一个添加到数组中,否则直接将
    list
    转换成数组,然后返回
  • 其他类型,也就是一个实体类了,直接获取

    list
    中的第一个元素返回(如果
    list
    集合的个数大于1则抛出异常)

  • ResultLoaderMap

    org.apache.ibatis.executor.loader.ResultLoaderMap
    :用于保存某个对象中所有的延迟加载

    构造方法

    public class ResultLoaderMap {
    /**
    * 用于延迟加载的加载器
    * key:属性名称
    * value:ResultLoader 加载器的封装对象 LoadPair
    */
    private final Map<String, LoadPair> loaderMap = new HashMap<>();
    }

    addLoader方法

    addLoader(String property, MetaObject metaResultObject, ResultLoader resultLoader)
    方法,用于添加一个需要延迟加载属性

    入参分别表示:需要延迟加载的属性名称、该属性所在的Java对象(也就是查询返回的结果对象)、延迟加载对应的加载器,方法如下:

    public void addLoader(String property, MetaObject metaResultObject, ResultLoader resultLoader) {
    // 获取第一个属性名称
    String upperFirst = getUppercaseFirstProperty(property);
    if (!upperFirst.equalsIgnoreCase(property) && loaderMap.containsKey(upperFirst)) {
    throw new ExecutorException("省略...");
    }
    loaderMap.put(upperFirst, new LoadPair(property, metaResultObject, resultLoader));
    }
    1. 如果

      property
      属性名称包含
      .
      点,且最前面一部分已经有对应的延迟加载对象了,则出现重复添加,需要抛出异常

    2. 将入参信息封装成

      LoadPair
      对象,并放入
      loaderMap

      关于

      LoadPair
      ,是ResultLoaderMap的一个内部类,里面有对序列化进行处理,最后还是调用
      ResultLoader
      load()
      方法,这里就不列出来了

    load方法

    load(String property)
    方法,用于触发该属性的延迟加载,方法如下:

    public boolean load(String property) throws SQLException {
    LoadPair pair = loaderMap.remove(property.toUpperCase(Locale.ENGLISH));
    if (pair != null) {
    pair.load();
    return true;
    }
    return false;
    }
    1. 先将该属性对应的延迟加载从
      loaderMap
      集合中删除
    2. 然后调用
      LoadPair
      load()
      方法,触发延迟加载,并设置查询结果设置到对象的属性中

    loadAll方法

    loadAll()
    方法,用于触发所有还没加载的延迟加载,方法如下:

    public void loadAll() throws SQLException {
    final Set<String> methodNameSet = loaderMap.keySet();
    String[] methodNames = methodNameSet.toArray(new String[methodNameSet.size()]);
    for (String methodName : methodNames) {
    load(methodName);
    }
    }

    ProxyFactory

    org.apache.ibatis.executor.loader.ProxyFactory
    :动态代理工厂接口

    public interface ProxyFactory {
    
    default void setProperties(Properties properties) {
    // NOP
    }
    
    Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration,
    ObjectFactory objectFactory, List<Class<?>> constructorArgTypes,
    List<Object> constructorArgs);
    }
    • 就定义了一个
      createProxy
      创建动态代理对象的方法,交由不同的子类去实现

    实现类如下图所示:

    回到Configuration全局配置对象中,你会发现默认使用的是

    JavassistProxyFactory
    实现类

    // Configuration.java
    protected ProxyFactory proxyFactory = new JavassistProxyFactory();

    JavassistProxyFactory

    org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory
    :实现ProxyFactory接口,基于
    javassist
    (一个开源的分析、编辑和创建Java字节码的类库)创建动态代理对象

    构造方法

    public class JavassistProxyFactory implements org.apache.ibatis.executor.loader.ProxyFactory {
    
    private static final String FINALIZE_METHOD = "finalize";
    private static final String WRITE_REPLACE_METHOD = "writeReplace";
    
    public JavassistProxyFactory() {
    try {
    // 加载 javassist.util.proxy.ProxyFactory 类
    Resources.classForName("javassist.util.proxy.ProxyFactory");
    } catch (Throwable e) {
    throw new IllegalStateException(
    "Cannot enable lazy loading because Javassist is not available. Add Javassist to your classpath.",
    e);
    }
    }
    }
    • 加载 javassist.util.proxy.ProxyFactory

    createProxy方法

    createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs)
    方法

    创建动态代理对象的入口,方法如下:

    @Override
    public Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration,
    ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    // <1> 创建动态代实例对象
    return EnhancedResultObjectProxyImpl.createProxy(target, lazyLoader, configuration,
    objectFactory, constructorArgTypes, constructorArgs);
    }

    内部直接调用

    EnhancedResultObjectProxyImpl
    createProxy
    方法

    crateProxy静态方法

    crateProxy(Class<?> type, MethodHandler callback, List<Class<?>> constructorArgTypes, List<Object> constructorArgs)
    方法

    用于创建一个动态代理的实例对象,并设置

    MethodHandler
    方法增强器,方法如下:

    static Object crateProxy(Class<?> type, MethodHandler callback, List<Class<?>> constructorArgTypes,
    List<Object> constructorArgs) {
    
    // <3.1> 创建 ProxyFactory 动态代理对象工厂
    ProxyFactory enhancer = new ProxyFactory();
    // <3.2> 设置父类,需要代理的类对象
    enhancer.setSuperclass(type);
    
    // <3.3> 和序列化相关
    try {
    // 获取需要代理的类对象中的 writeReplace 方法
    type.getDeclaredMethod(WRITE_REPLACE_METHOD);
    // ObjectOutputStream will call writeReplace of objects returned by writeReplace
    if (LogHolder.log.isDebugEnabled()) {
    LogHolder.log.debug(WRITE_REPLACE_METHOD + " method was found on bean " + type + ", make sure it returns this");
    }
    } catch (NoSuchMethodException e) {
    // 如果没有 writeReplace 方法,则设置接口为 WriteReplaceInterface
    enhancer.setInterfaces(new Class[] { WriteReplaceInterface.class });
    } catch (SecurityException e) {
    // nothing to do here
    }
    
    Object enhanced;
    Class<?>[] typesArray = constructorArgTypes.toArray(new Class[constructorArgTypes.size()]);
    Object[] valuesArray = constructorArgs.toArray(new Object[constructorArgs.size()]);
    try {
    // <3.4> 创建动态代理实例对象
    enhanced = enhancer.create(typesArray, valuesArray);
    } catch (Exception e) {
    throw new ExecutorException("Error creating lazy proxy.  Cause: " + e, e);
    }
    // <3.5> 设置动态代理实例对象的 MethodHandler 方法增强器
    ((Proxy) enhanced).setHandler(callback);
    return enhanced;
    }
    1. 创建 ProxyFactory 动态代理对象工厂
    2. 设置父类,需要代理的类对象
    3. 设置和序列化相关配置
    4. 创建动态代理实例对象,传入代理类对象的构造方法的入参类型数组和入参数组
    5. 设置动态代理实例对象的
      MethodHandler
      方法增强器

    EnhancedResultObjectProxyImpl

    JavassistProxyFactory的内部类,动态代理对象的

    MethodHandler
    方法增强器

    构造方法
    private static class EnhancedResultObjectProxyImpl implements MethodHandler {
    
    private final Class<?> type;
    private final ResultLoaderMap lazyLoader;
    /**
    * 开启时,任一方法的调用都会加载该对象的所有延迟加载属性,默认false
    */
    private final boolean aggressive;
    private final Set<String> lazyLoadTriggerMethods;
    private final ObjectFactory objectFactory;
    private final List<Class<?>> constructorArgTypes;
    private final List<Object> constructorArgs;
    
    private EnhancedResultObjectProxyImpl(Class<?> type, ResultLoaderMap lazyLoader, Configuration configuration,
    ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    this.type = type;
    this.lazyLoader = lazyLoader;
    this.aggressive = configuration.isAggressiveLazyLoading();
    this.lazyLoadTriggerMethods = configuration.getLazyLoadTriggerMethods();
    this.objectFactory = objectFactory;
    this.constructorArgTypes = constructorArgTypes;
    this.constructorArgs = constructorArgs;
    }
    }
    • 我们主要看到
      ResultLoaderMap lazyLoader
      属性,里面保存了需要延迟加载的属性和加载器
    createProxy方法

    createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs)
    方法

    创建动态代理实例对象,方法如下:

    public static Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration,
    ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    final Class<?> type = target.getClass();
    // <2> 创建方法的增强器
    EnhancedResultObjectProxyImpl callback = new EnhancedResultObjectProxyImpl(type, lazyLoader, configuration,
    objectFactory, constructorArgTypes, constructorArgs);
    // <3> 创建动态代理实例对象,设置方法的增强器
    Object enhanced = crateProxy(type, callback, constructorArgTypes, constructorArgs);
    // <4> 将 target 的属性值复制到 enhanced 动态代实例对象中
    PropertyCopier.copyBeanProperties(type, target, enhanced);
    return enhanced;
    }

    这个方法在

    JavassistProxyFactory
    createProxy
    方法被调用,然后自己内部又调用
    JavassistProxyFactory
    的静态
    createProxy
    方法,这里我已经按序号标明了步骤

    1. 创建
      EnhancedResultObjectProxyImpl
      方法的增强器
      callback
    2. 创建动态代理实例对象,并设置方法的增强器为
      callback
      ,调用的是上面的静态
      createProxy
      方法
    3. target
      的属性值复制到
      enhanced
      动态代实例对象中
    invoke方法

    javassist.util.proxy.MethodHandler
    方法增强器的而实现方法,代理对象的方法都会进入这个方法

    @Override
    public Object invoke(Object enhanced, Method method, Method methodProxy, Object[] args) throws Throwable {
    final String methodName = method.getName();
    try {
    synchronized (lazyLoader) {
    // <1> 如果方法名为 writeReplace,和序列化相关
    if (WRITE_REPLACE_METHOD.equals(methodName)) {
    Object original;
    if (constructorArgTypes.isEmpty()) {
    original = objectFactory.create(type);
    } else {
    original = objectFactory.create(type, constructorArgTypes, constructorArgs);
    }
    // 从动态代理实例对象中复制属性值到 original 中
    PropertyCopier.copyBeanProperties(type, enhanced, original);
    if (lazyLoader.size() > 0) {
    return new JavassistSerialStateHolder(original, lazyLoader.getProperties(),
    objectFactory,constructorArgTypes, constructorArgs);
    } else {
    return original;
    }
    } else { // <2> 加载延迟加载的属性
    if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) {
    // <2.1> 如果开启了任一方法的调用都会加载该对象的所有延迟加载属性,或者是 "equals", "clone", "hashCode", "toString" 其中的某个方法
    if (aggressive || lazyLoadTriggerMethods.contains(methodName)) {
    // 加载所有延迟加载的属性
    lazyLoader.loadAll();
    } else if (PropertyNamer.isSetter(methodName)) {
    // <2.2> 如果为 setter 方法,从需要延迟加载属性列表中移除
    final String property = PropertyNamer.methodToProperty(methodName);
    lazyLoader.remove(property);
    } else if (PropertyNamer.isGetter(methodName)) {
    // <2.3> 如果调用了 getter 方法,则执行延迟加载,从需要延迟加载属性列表中移除
    final String property = PropertyNamer.methodToProperty(methodName);
    if (lazyLoader.hasLoader(property)) {
    // 加载该属性值
    lazyLoader.load(property);
    }
    }
    }
    }
    }
    // <3> 继续执行原方法
    return methodProxy.invoke(enhanced, args);
    } catch (Throwable t) {
    throw ExceptionUtil.unwrapThrowable(t);
    }
    }

    先给

    ResultLoaderMap lazyLoader
    添加
    synchronized
    关键字,保证线程安全

    1. 如果加强的方法是

      writeReplace
      ,则进行一些序列化相关的操作,暂不分析,其实是没看懂~

    2. 如果

      lazyLoader
      中有延迟加载的属性,并且加强的方法不是
      finalize

      如果开启了任一方法的调用都会加载该对象的所有延迟加载属性,或者是
      equals clone hashCode toString
      其中的某个方法,则触发所有的延迟加载
    3. 否则,如果是属性的setter方法,则从
      lazyLoader
      中将该属性的延迟加载删除(如果存在),因为主动设置了这个属性值,则需要取消该属性的延迟加载
    4. 否则,如果是属性的getter方法,则执行延迟加载(会将结果设置到该对象的这个属性中),里面也会从
      lazyLoader
      中将该属性的延迟加载删除
  • 继续执行原方法

  • 到这里,延迟加载已经实现了

    CglibProxyFactory

    org.apache.ibatis.executor.loader.cglib.CglibProxyFactory
    :实现ProxyFactory接口,基于
    cglib
    (一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口)创建动态代理对象

    实现方式和

    JavassistProxyFactory
    类似,这里就不进行分析了,感兴趣的可以看一下

    总结

    本文分析了 MyBatis 中延迟加载的实现方法,在 DefaultResultSetHandler 映射结果集的过程中,如果返回对象有属性是嵌套子查询,且需要延迟加载,则通过

    JavassistProxyFactory
    为返回结果创建一个动态代理对象,并设置
    MethodHandler
    方法增强器为
    EnhancedResultObjectProxyImpl
    对象

    其中传入

    ResultLoaderMap
    对象,该对象保存了这个结果对象中所有的
    ResultLoader
    延迟加载

    EnhancedResultObjectProxyImpl
    中拦截结果对象的方法,进行增强处理,通过
    ResultLoader
    延迟加载器获取到该属性值,然后从
    ResultLoaderMap
    中删除,在你调用该属性的getter方法时才加载数据,这样就实现了延迟加载

    好了,对于 MyBatis 的整个 SQL 执行过程我们已经全部分析完了,其中肯定有不对或者迷惑的地方,欢迎指正!!!感谢大家的阅读!!!:smilesmilesmile:

    参考文章:芋道源码《精尽 MyBatis 源码分析》

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: