mybatis 源码

1 架构分析

2 核心流程

Session模块属于最上层的模块,主要用于提供sql执行的接口以及配置文件的加载。

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。

例:

java 复制代码
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

思考为什么要通过builder来构造factory?

通过构造模式构建复杂对象。然后通过工厂模式构建单一对象。这个过程实际就是一个解耦的过程,将工厂和session的构建独立开来。

既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。

例:指定mapper对象的方法执行sql

java 复制代码
try (SqlSession session = sqlSessionFactory.openSession()) {
  Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
}

例:通过mapper对象执行sql

java 复制代码
try (SqlSession session = sqlSessionFactory.openSession()) {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  Blog blog = mapper.selectBlog(101);
}

关键类说明:

SqlSessionFactory:用于创建SqlSession对象。

SqlSessionFactoryBuilder:根据配置文件创建SqlSessionFactory。包括mapper.xml文件的解析。

SqlSession:用于执行sql。

2.1 SqlSessionFactoryBuilder解析mapper.xml文件中的信息

cache 配置加载

以mybatis的cache功能为例:

参考:mybatis文档

在org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XNode context)方法中解析了xml文件。

关注 cacheElement(XNode context)方法,该方法解析了缓存配置

首先我们看type属性的解析。

根据官方文档:

type属性,配置的是org.apache.ibatis.cache.Cache接口的实现类。默认实现PerpetualCache.class

statement加载

每个sql(select/delete/insert/update标签中的内容)都会对应一个MappedStatement对象,存储在Configuration对象中。

注意所有的statement都存储在一个全局的configruation对象的Map<String, MappedStatement> mappedStatements属性中(key为MappedStatement的id)。根据下面的applyCurrentNamespace方法可以看出id属性的格式是"namespace"+...+"id(crud标签中的id)",如com.learn.learn.TestMapper.selectOne;

java 复制代码
public String applyCurrentNamespace(String base, boolean isReference) {
    if (base == null) {
        return null;
    }
    if (isReference) {
        // is it qualified with any namespace yet?
        if (base.contains(".")) {
            return base;
        }
    } else {
        // is it qualified with this namespace yet?
        if (base.startsWith(currentNamespace + ".")) {
            return base;
        }
        if (base.contains(".")) {
            throw new BuilderException("Dots are not allowed in element names, please remove it from " + base);
        }
    }
    return currentNamespace + "." + base;
}

2.2 SqlSession

SqlSession对象由SqlSessionFactory对象创建,但是具体执行SQL的对象是SqlSession对象中的Executor对象

例:

根据代码可知,默认的executor是:SimpleExecutor

根据上述代码可以得知,如果开启了二级缓存,则会在原有的执行器外包装一层CachingExecutor。即配置:settings.cacheEnabled。除此之外还需要在statement中配置cache,因为CachingExecutor这个执行器会需要从statement中获取cache,并且操作这个cache。

从上述代码中的最后一行可以看出,执行还做了一个操作:

这个个步骤根据源码分析就是为executor生成一个个动态代理对象,使得配置的插件功能能够生效。

executor

以CacheExecutor为例,可以看出如果开启了二级缓存,那么查询会先去cache查询,没有再去被包装的executor(delegate)查询,并将结果同步到缓存中。

Executor接口除了CacheExecutor之外还有另一个实现类BaseExecutor,该类是一个抽象类,提供了一些模板方法。这里我们阅读一个query方法:

java 复制代码
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler,
                         CacheKey key, BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    if (closed) {
        throw new ExecutorException("Executor was closed.");
    }
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
        clearLocalCache();
    }
    List<E> list;
    try {
        //查询深度,避免递归查询重复处理缓存
        queryStack++;
        //查询一级缓存
        list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
        if (list != null) {
            handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
        } else {
            //查询数据库
            list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
        }
    } finally {
        queryStack--;
    }
    if (queryStack == 0) {
        for (DeferredLoad deferredLoad : deferredLoads) {
            deferredLoad.load();
        }
        // issue #601
        deferredLoads.clear();
        if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
            // issue #482
            clearLocalCache();
        }
    }
    return list;
}


  private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds,
      ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    //占位符,标记缓存中已经有数据了,只是查询还没有完成,相同的操作就不需要再查询数据库了
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
      localCache.removeObject(key);
    }
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
  }

从上述代码看出在BaseExecutor中仍旧是先去查了缓存,没有再去查数据库。这里就引出了二级缓存的概念。

在探究二级缓存之前,上述的方法中有一个queryStack属性,该属性的作用是什么?并且在数据库查询的方法中,为什么要有一个占位符?

设想一个场景:

1 查询学校: 正常查询,加入一级缓存

2 查询学校的学生:正常查询,加入一级缓存

3 查询学生的学校:?从缓存中获取还是再查数据库?延迟加载,从缓存中获取

在并发请求的情况下,同一个session运行多个请求,占位符就用来标记一级缓存中已经有数据了,但是操作还没有完成,相同的数据就不用再查数据库了。

那么queryStack的作用呢?

该作用是在嵌套查询的过程中,防止缓存被误删。

二级缓存

为什么要分两级缓存?这两级的区别在哪里?

二级缓存(即cache)是进程级别的,而一级缓存(即localCache)是session级别的。

SQL语句的执行过程

在上述的二级缓存之后,具体执行sql的executor可根据配置选择,默认的实现是SimpleExecutor。以该类为例分析源码:

java 复制代码
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler,
                           BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
    Configuration configuration = ms.getConfiguration();
    //默认创建PreparedStatementHandler,同时完成parameterHandler和resultSethandler的实例化
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler,
                                                                 boundSql);
    //获取一个statement对象,处理占位符
    stmt = prepareStatement(handler, ms.getStatementLog());
    //执行查询
    return handler.query(stmt, resultHandler);
} finally {
    closeStatement(stmt);
}
}

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement,
                                            Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject,
                                                                    rowBounds, resultHandler, boundSql);
    return (StatementHandler) interceptorChain.pluginAll(statementHandler);
}

可以看到具体执行statement的是StatementHandler这个类的对象。并从创建handler的方法中可以看出返回的handler实际上是一个动态代理对象,所以在执行SQL时可以通过插件的方式增强代码,比如在sql执行的前后自定义自己的操作。

这里注意创建StatementHandler的方法中,创建的是RoutingStatementHandler,这其实一个静态代理类:

java 复制代码
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,
                               ResultHandler resultHandler, BoundSql boundSql) {

    switch (ms.getStatementType()) {
        case STATEMENT:
            delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
        case PREPARED:
            delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
        case CALLABLE:
            delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
        default:
            throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }

}

根据源码可以看出根据statement的类型不同,statementHandler分成三类:

SimpleStatementHandler:执行静态sql的执行器

PreparedStatementHandler:执行可动态配置参数的sql,比如:select * from test where id = {id}

CallableStatementHandler:执行存储过程的执行器

结果映射

以PreparedStatementHandler为例,分析源码:

java 复制代码
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    return resultSetHandler.handleResultSets(ps);
}

我们可以看出ps执行之后,是通过resultSetHandler来处理了ps返回的结果集。

获取Mapper并执行sql

在实际开发中,我们使用的都是mapper对象。所以接下来分析如何获取到mapper对象。

getMapper方法源码:

java 复制代码
@Override
public <T> T getMapper(Class<T> type) {
    return configuration.getMapper(type, this);
}

confifuration.getMapper方法:

java 复制代码
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
}

mapperRegistry.getMapper方法:

java 复制代码
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
        throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
        return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
        throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
}

实际的mapper对象是由对象工厂创建的。

java 复制代码
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}

而工厂对象创建的是mapper对象的动态代理对象。为什么不直接返回mapper对象,却返回一个代理?

java 复制代码
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
        //如果调用的是toString hashCode equal getClass等方法,则无需走到执行sql的流程
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        }
        //sql方法走的是这里
        return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
    } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
    }
}

private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
    try {
        return methodCache.computeIfAbsent(method, m -> {
            //非默认方法
            if (!m.isDefault()) {
                return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
            }
            //default方法
            try {
                return new DefaultMethodInvoker(getMethodHandleJava9(method));
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        });
    } catch (RuntimeException re) {
        Throwable cause = re.getCause();
        throw cause == null ? re : cause;
    }
}

真正执行sql方法的地方在:

java 复制代码
@Override
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
    return mapperMethod.execute(sqlSession, args);
}

execut方法内容:

java 复制代码
public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
        case INSERT: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.insert(command.getName(), param));
            break;
        }
        case UPDATE: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.update(command.getName(), param));
            break;
        }
        case DELETE: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.delete(command.getName(), param));
            break;
        }
        case SELECT:
            if (method.returnsVoid() && method.hasResultHandler()) {
                executeWithResultHandler(sqlSession, args);
                result = null;
            } else if (method.returnsMany()) {
                result = executeForMany(sqlSession, args);
            } else if (method.returnsMap()) {
                result = executeForMap(sqlSession, args);
            } else if (method.returnsCursor()) {
                result = executeForCursor(sqlSession, args);
            } else {
                Object param = method.convertArgsToSqlCommandParam(args);
                result = sqlSession.selectOne(command.getName(), param);
                if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) {
                    result = Optional.ofNullable(result);
                }
            }
            break;
        case FLUSH:
            result = sqlSession.flushStatements();
            break;
        default:
            throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
        throw new BindingException("Mapper method '" + command.getName()
                                   + "' attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
}

3 缓存模块

在impl中提供了一个PrepetualCache,其是Cache的实现类。但是其功能本身十分简单,其功能实现是基于map对象实现的。为了使PrepetualCache功能更加强大,mybatis通过装饰器模式,在decorators包下提供了许多装饰器。所以如果要实现我们自己的缓存,可以自行实现Cache接口。

CacheKey

根据之前二级缓存的代码来看,查询cache的的key是CacheKey对象。

java 复制代码
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler)
throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

CacheKey的创建方法:

java 复制代码
@Override
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
    if (closed) {
        throw new ExecutorException("Executor was closed.");
    }
    CacheKey cacheKey = new CacheKey();
    cacheKey.update(ms.getId());//methodName
    cacheKey.update(rowBounds.getOffset());//分页处理
    cacheKey.update(rowBounds.getLimit());//分页处理
    cacheKey.update(boundSql.getSql());//sql
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
    // mimic DefaultParameterHandler logic
    MetaObject metaObject = null;
    //查询参数
    for (ParameterMapping parameterMapping : parameterMappings) {
        if (parameterMapping.getMode() != ParameterMode.OUT) {
            Object value;
            String propertyName = parameterMapping.getProperty();
            if (parameterMapping.hasValue()) {
                value = parameterMapping.getValue();
            } else if (boundSql.hasAdditionalParameter(propertyName)) {
                value = boundSql.getAdditionalParameter(propertyName);
            } else if (parameterObject == null) {
                value = null;
            } else {
                ParamNameResolver paramNameResolver = ms.getParamNameResolver();
                if (paramNameResolver != null
                    && typeHandlerRegistry.hasTypeHandler(paramNameResolver.getType(paramNameResolver.getNames()[0]))
                    || typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                    value = parameterObject;
                } else {
                    if (metaObject == null) {
                        metaObject = configuration.newMetaObject(parameterObject);
                    }
                    value = metaObject.getValue(propertyName);
                }
            }
            cacheKey.update(value);
        }
    }
    if (configuration.getEnvironment() != null) {
        // issue #176
        cacheKey.update(configuration.getEnvironment().getId());
    }
    return cacheKey;
}

4 数据源模块

数据源的创建是通过工厂模式创建的:

java 复制代码
private void environmentsElement(XNode context) throws Exception {
    if (context == null) {
        return;
    }
    if (environment == null) {
        environment = context.getStringAttribute("default");
    }
    for (XNode child : context.getChildren()) {
        String id = child.getStringAttribute("id");
        if (isSpecifiedEnvironment(id)) {
            TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
            DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
            DataSource dataSource = dsFactory.getDataSource();
            Environment.Builder environmentBuilder = new Environment.Builder(id).transactionFactory(txFactory)
            .dataSource(dataSource);
            configuration.setEnvironment(environmentBuilder.build());
            break;
        }
    }
}
java 复制代码
/**
 * @author Clinton Begin
 */
public interface DataSourceFactory {

    void setProperties(Properties props);

    DataSource getDataSource();

}

而Mybatis针对数据源工厂有三种实现:

JNDI DataSource(JndiDatasource)是一种通过Java命名和目录接口(JNDI)获取数据库连接的数据源配置方式,其核心在于将数据库连接的管理交给外部容器(如应用服务器或Web容器),实现连接信息的集中化配置与解耦。

PoolDataSource:通过连接池管理数据库连接。

UnpooledDataSource:不通过连接池管理数据库连接。

java 复制代码
/**
 * @author Clinton Begin
 */
public class PooledDataSourceFactory extends UnpooledDataSourceFactory {

    public PooledDataSourceFactory() {
        this.dataSource = new PooledDataSource();
    }

}

通过源码可以看出,PoolDataSource继承了UnpooledDataSourceFactory。区别只是,创建的数据源是PooledDataSource还是UnpooledDataSource。

4.1 连接池数据源获取连接

两个DataSource的区别主要就集中在doGetConnection方法中。UnpooledDataSource每次都会直接新建一个连接,而PooledDataSource,创建连接时会去使用池中的连接。

java 复制代码
@Override
public Connection getConnection() throws SQLException {
return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection();
}

private PooledConnection popConnection(String username, String password) throws SQLException {
    boolean countedWait = false;
    PooledConnection conn = null;
    long t = System.currentTimeMillis();
    int localBadConnectionCount = 0;

    while (conn == null) {
      lock.lock();
      try {

        if (!state.idleConnections.isEmpty()) {
          //如果闲置池不为空,则从闲置队列中取出一个连接
          // Pool has available connection
          conn = state.idleConnections.remove(0);
          if (log.isDebugEnabled()) {
            log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");
          }
        } else if (state.activeConnections.size() < poolMaximumActiveConnections) {
          //闲置池空了,那么判断是否需要创建新连接
          // 如果连接池中的连接数量小于最大连接数,则创建一个新连接
          // Pool does not have available connection and can create a new connection
          conn = new PooledConnection(dataSource.getConnection(), this);
          if (log.isDebugEnabled()) {
            log.debug("Created connection " + conn.getRealHashCode() + ".");
          }
        } else {
          //连接池空了,且连接池中的连接数量已经达到最大值,此时就不能再创建连接了
          // Cannot create new connection
          //获取最早创建的连接
          PooledConnection oldestActiveConnection = state.activeConnections.get(0);
          // 获取最早创建的连接的创建时间
          long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();
          //如果创建时间超过最大允许时间,则认为该连接已经超时
          if (longestCheckoutTime > poolMaximumCheckoutTime) {
            // Can claim overdue connection
            //统计超时连接信息
            state.claimedOverdueConnectionCount++;
            state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;
            state.accumulatedCheckoutTime += longestCheckoutTime;
            //删除超时连接
            state.activeConnections.remove(oldestActiveConnection);
            //如果连接不是自动提交,则回滚
            if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
              try {
                //回滚
                oldestActiveConnection.getRealConnection().rollback();
              } catch (SQLException e) {
                /*
                 * Just log a message for debug and continue to execute the following statement like nothing happened.
                 * Wrap the bad connection with a new PooledConnection, this will help to not interrupt current
                 * executing thread and give current thread a chance to join the next competition for another valid/good
                 * database connection. At the end of this loop, bad {@link @conn} will be set as null.
                 */
                log.debug("Bad connection. Could not roll back");
              }
            }
            //创建新的连接,但是连接还不是完全可用
            conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);
            conn.setCreatedTimestamp(oldestActiveConnection.getCreatedTimestamp());
            conn.setLastUsedTimestamp(oldestActiveConnection.getLastUsedTimestamp());
            oldestActiveConnection.invalidate();
            if (log.isDebugEnabled()) {
              log.debug("Claimed overdue connection " + conn.getRealHashCode() + ".");
            }
          } else {
            // 如果创建时间没有超过最大允许时间,则判断为正常连接,
            // Must wait
            try {
              //等待数增加
              if (!countedWait) {
                state.hadToWaitCount++;
                countedWait = true;
              }
              if (log.isDebugEnabled()) {
                log.debug("Waiting as long as " + poolTimeToWait + " milliseconds for connection.");
              }
              long wt = System.currentTimeMillis();
              //等待连接
              if (!condition.await(poolTimeToWait, TimeUnit.MILLISECONDS)) {
                log.debug("Wait failed...");
              }
              state.accumulatedWaitTime += System.currentTimeMillis() - wt;
            } catch (InterruptedException e) {
              // set interrupt flag
              Thread.currentThread().interrupt();
              break;
            }
          }
        }
        //连接获取成功
        if (conn != null) {
          // ping to server and check the connection is valid or not
          if (conn.isValid()) {
            //连接有效
            //如果连接不是自动提交,则回滚
            if (!conn.getRealConnection().getAutoCommit()) {
              conn.getRealConnection().rollback();
            }
            //获取连接类型
            conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password));
            conn.setCheckoutTimestamp(System.currentTimeMillis());
            conn.setLastUsedTimestamp(System.currentTimeMillis());
            state.activeConnections.add(conn);
            state.requestCount++;
            state.accumulatedRequestTime += System.currentTimeMillis() - t;
          } else {
            //连接无效
            if (log.isDebugEnabled()) {
              log.debug("A bad connection (" + conn.getRealHashCode()
                  + ") was returned from the pool, getting another connection.");
            }
            state.badConnectionCount++;
            localBadConnectionCount++;
            //继续下一个循环
            conn = null;
            //超过了失败次数
            if (localBadConnectionCount > poolMaximumIdleConnections + poolMaximumLocalBadConnectionTolerance) {
              if (log.isDebugEnabled()) {
                log.debug("PooledDataSource: Could not get a good connection to the database.");
              }
              throw new SQLException("PooledDataSource: Could not get a good connection to the database.");
            }
          }
        }
      } finally {
        lock.unlock();
      }

    }

    //获取连接失败
    if (conn == null) {
      if (log.isDebugEnabled()) {
        log.debug("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
      }
      throw new SQLException(
          "PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
    }

    return conn;
  }

可以看出获取连接是通过自旋的方式来获取连接。

4.2 释放连接

需要注意:PooledDataSource返回的连接是PooledConnection,这个类其实也是一个代理类。查看其invoke方法:

java 复制代码
//空闲连接队列
protected final List<PooledConnection> idleConnections = new ArrayList<>();
//使用中的连接队列
protected final List<PooledConnection> activeConnections = new ArrayList<>();

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    String methodName = method.getName();
    //这里关闭方法,并不释放连接,而是将其放回到连接池中
    if (CLOSE.equals(methodName)) {
        dataSource.pushConnection(this);
        return null;
    }
    try {
        if (!Object.class.equals(method.getDeclaringClass())) {
            // issue #579 toString() should never fail
            // throw an SQLException instead of a Runtime
            checkConnection();
        }
        return method.invoke(realConnection, args);
    } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
    }

}
java 复制代码
protected void pushConnection(PooledConnection conn) throws SQLException {

    lock.lock();
    try {
        //移除当前连接
        state.activeConnections.remove(conn);
        if (conn.isValid()) {
            //连接有效

            if (state.idleConnections.size() < poolMaximumIdleConnections
                && conn.getConnectionTypeCode() == expectedConnectionTypeCode) {
                //空闲连接数小于最大空闲连接数 且 当前连接类型一致

                state.accumulatedCheckoutTime += conn.getCheckoutTime();
                if (!conn.getRealConnection().getAutoCommit()) {
                    //回滚
                    conn.getRealConnection().rollback();
                }
                PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this);
                //加入空闲队列
                state.idleConnections.add(newConn);
                newConn.setCreatedTimestamp(conn.getCreatedTimestamp());
                newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());
                conn.invalidate();
                if (log.isDebugEnabled()) {
                    log.debug("Returned connection " + newConn.getRealHashCode() + " to pool.");
                }
                //通知获取连接的线程 取消等待,获取连接
                condition.signal();
            } else {

                //连接无效
                state.accumulatedCheckoutTime += conn.getCheckoutTime();
                if (!conn.getRealConnection().getAutoCommit()) {
                    //回滚
                    conn.getRealConnection().rollback();
                }
                //关闭连接 
                conn.getRealConnection().close();
                if (log.isDebugEnabled()) {
                    log.debug("Closed connection " + conn.getRealHashCode() + ".");
                }
                //连接失效
                conn.invalidate();
            }
        } else {
            //连接无效
            if (log.isDebugEnabled()) {
                log.debug("A bad connection (" + conn.getRealHashCode()
                          + ") attempted to return to the pool, discarding connection.");
            }
            state.badConnectionCount++;
        }
    } finally {
        lock.unlock();
    }
}

5 事务模块

根据BaseExecutor的源码可知,创建连接并不是直接通过数据源创建的,而是通过事务创建的:

java 复制代码
shiwuprotected Connection getConnection(Log statementLog) throws SQLException {
    Connection connection = transaction.getConnection();
    if (statementLog.isDebugEnabled()) {
        return ConnectionLogger.newInstance(connection, statementLog, queryStack);
    }
    return connection;
}

事务通过数据源创建连接:

java 复制代码
protected void openConnection() throws SQLException {
if (log.isDebugEnabled()) {
    log.debug("Opening JDBC Connection");
}
connection = dataSource.getConnection();
if (level != null) {
    connection.setTransactionIsolation(level.getLevel());
}
setDesiredAutoCommit(autoCommit);
}

在mybatis中提供了两种事务:jdbc和managed。jdbc是通过jdbc连接直接提交实现的。而managed是交给容器(比如Spring)去管理。

6 反射模块

6.1 Reflector

每个Reflector对象都对应一个class对象,缓存class的内容。Reflector的核心属性:

java 复制代码
//类
private final Class<?> clazz;
//可读属性集合,就是存在getter方法的属性
private final String[] readablePropertyNames;
//可写属性集合,就是存在setter方法的属性
private final String[] writablePropertyNames;
//setter方法集合
private final Map<String, Invoker> setMethods = new HashMap<>();
//getter方法集合
private final Map<String, Invoker> getMethods = new HashMap<>();
//相应setter方法的参数类型,key是属性名称,value是setter方法的参数类型
private final Map<String, Entry<Type, Class<?>>> setTypes = new HashMap<>();
//相应getter方法的参数类型,key是属性名称,value是getter方法的参数类型
private final Map<String, Entry<Type, Class<?>>> getTypes = new HashMap<>();
//默认构造方法
private Constructor<?> defaultConstructor;
//所有属性的名称合集
private final Map<String, String> caseInsensitivePropertyMap = new HashMap<>();

6.2 invoker

Invoker接口用于设置对象的属性值。

java 复制代码
public interface Invoker {
    //执行method,如getter setter
    Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;

    //获取返回值类型
    Class<?> getType();
}

6.3 TypeParameterResolver

解决复杂对象的解析,比如user对象中存在集合等情况。

6.4 ObjectFactory

DefaultObjectFactory是ObjectFactory的默认实现。ObjectFactory是用来创建对象的工厂。

6.5 Properties

propertis包下的工具主要用于复杂属性操作。

6.6 ObjectWrapper

对对象进行包裹,可以通过这个类来实现对属性的修改和读取。

6.7 反射模块的使用

参考:DefaultResultSetHandlers方法:

java 复制代码
/*
 *    Copyright 2009-2025 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       https://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor.resultset;

import ... // 多个导入语句

/**
 * 默认的结果集处理器实现类,负责处理数据库查询结果并将其映射为Java对象
 * @author Clinton Begin
 * @author Eduardo Macarron
 * @author Iwao AVE!
 * @author Kazuki Shimizu
 * @author Willie Scholtz
 */
public class DefaultResultSetHandler implements ResultSetHandler {

  private static final Object DEFERRED = new Object(); // 延迟加载标记

  // 执行器、配置、映射语句等核心组件
  private final Executor executor;
  private final Configuration configuration;
  private final MappedStatement mappedStatement;
  private final RowBounds rowBounds;
  private final ParameterHandler parameterHandler;
  private final ResultHandler<?> resultHandler;
  private final BoundSql boundSql;
  private final TypeHandlerRegistry typeHandlerRegistry;
  private final ObjectFactory objectFactory;
  private final ReflectorFactory reflectorFactory;

  // 待处理关系跟踪器,用于处理嵌套结果中的集合属性创建延迟情况
  private final Map<Object, PendingRelation> pendingPccRelations = new IdentityHashMap<>();

  // 嵌套结果对象缓存,避免重复构建相同对象
  private final Map<CacheKey, Object> nestedResultObjects = new HashMap<>();
  // 祖先对象缓存,防止循环引用导致无限递归
  private final Map<String, Object> ancestorObjects = new HashMap<>();
  private Object previousRowValue; // 上一行数据值,用于有序结果优化性能

  // 多结果集支持相关字段
  private final Map<String, ResultMapping> nextResultMaps = new HashMap<>();
  private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<>();

  // 自动映射缓存,提高自动映射效率
  private final Map<String, List<UnMappedColumnAutoMapping>> autoMappingsCache = new HashMap<>();
  private final Map<String, List<String>> constructorAutoMappingColumns = new HashMap<>();

  // 构造函数映射标识位,减少内存占用
  private boolean useConstructorMappings;

  /**
   * 内部静态类,表示待处理的关系映射信息
   */
  private static class PendingRelation {
    public MetaObject metaObject;         // 元对象实例
    public ResultMapping propertyMapping; // 属性映射信息
  }

  /**
   * 未映射列的自动映射信息封装类
   */
  private static class UnMappedColumnAutoMapping {
    private final String column;           // 数据库列名
    private final String property;         // Java属性名
    private final TypeHandler<?> typeHandler; // 类型处理器
    private final boolean primitive;       // 是否基本类型

    public UnMappedColumnAutoMapping(String column, String property, TypeHandler<?> typeHandler, boolean primitive) {
      this.column = column;
      this.property = property;
      this.typeHandler = typeHandler;
      this.primitive = primitive;
    }
  }

  /**
   * 构造函数初始化所有必需的核心组件
   */
  public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler,
      ResultHandler<?> resultHandler, BoundSql boundSql, RowBounds rowBounds) {
    this.executor = executor;
    this.configuration = mappedStatement.getConfiguration();
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;
    this.parameterHandler = parameterHandler;
    this.boundSql = boundSql;
    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();
    this.reflectorFactory = configuration.getReflectorFactory();
    this.resultHandler = resultHandler;
  }

  /**
   * 处理存储过程输出参数的方法
   */
  @Override
  public void handleOutputParameters(CallableStatement cs) throws SQLException {
    final Object parameterObject = parameterHandler.getParameterObject();
    final MetaObject metaParam = configuration.newMetaObject(parameterObject);
    final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    for (int i = 0; i < parameterMappings.size(); i++) {
      final ParameterMapping parameterMapping = parameterMappings.get(i);
      if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
        if (ResultSet.class.equals(parameterMapping.getJavaType())) {
          handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam);
        } else {
          final String property = parameterMapping.getProperty();
          TypeHandler<?> typeHandler = parameterMapping.getTypeHandler();
          if (typeHandler == null) {
            Type javaType = parameterMapping.getJavaType();
            if (javaType == null || javaType == Object.class) {
              javaType = metaParam.getGenericSetterType(property).getKey();
            }
            JdbcType jdbcType = parameterMapping.getJdbcType();
            typeHandler = typeHandlerRegistry.getTypeHandler(javaType, jdbcType, null);
            if (typeHandler == null) {
              typeHandler = typeHandlerRegistry.getTypeHandler(jdbcType);
              if (typeHandler == null) {
                typeHandler = ObjectTypeHandler.INSTANCE;
              }
            }
          }
          metaParam.setValue(property, typeHandler.getResult(cs, i + 1));
        }
      }
    }
  }

  /**
   * 处理REF CURSOR类型的输出参数
   */
  private void handleRefCursorOutputParameter(ResultSet rs, ParameterMapping parameterMapping, MetaObject metaParam)
      throws SQLException {
    if (rs == null) {
      return;
    }
    try {
      final String resultMapId = parameterMapping.getResultMapId();
      final ResultMap resultMap = configuration.getResultMap(resultMapId);
      final ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration);
      if (this.resultHandler == null) {
        final DefaultResultHandler resultHandler = new DefaultResultHandler(objectFactory);
        handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
        metaParam.setValue(parameterMapping.getProperty(), resultHandler.getResultList());
      } else {
        handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
      }
    } finally {
      closeResultSet(rs); // 关闭结果集资源
    }
  }

  /**
   * 主要入口方法,处理多个结果集并将它们转换成Java对象列表
   */
  @Override
  public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

    final List<Object> multipleResults = new ArrayList<>();

    int resultSetCount = 0;
    ResultSetWrapper rsw = getFirstResultSet(stmt);

    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
    while (rsw != null && resultMapCount > resultSetCount) {
      ResultMap resultMap = resultMaps.get(resultSetCount);
      handleResultSet(rsw, resultMap, multipleResults, null);
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }

    String[] resultSets = mappedStatement.getResultSets();
    if (resultSets != null) {
      while (rsw != null && resultSetCount < resultSets.length) {
        ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
        if (parentMapping != null) {
          String nestedResultMapId = parentMapping.getNestedResultMapId();
          ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
          handleResultSet(rsw, resultMap, null, parentMapping);
        }
        rsw = getNextResultSet(stmt);
        cleanUpAfterHandlingResultSet();
        resultSetCount++;
      }
    }

    return collapseSingleResultList(multipleResults);
  }

  /**
   * 处理游标类型的结果集
   */
  @Override
  public <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling cursor results").object(mappedStatement.getId());

    ResultSetWrapper rsw = getFirstResultSet(stmt);

    List<ResultMap> resultMaps = mappedStatement.getResultMaps();

    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
    if (resultMapCount != 1) {
      throw new ExecutorException("Cursor results cannot be mapped to multiple resultMaps");
    }

    ResultMap resultMap = resultMaps.get(0);
    return new DefaultCursor<>(this, resultMap, rsw, rowBounds);
  }

  /**
   * 获取第一个结果集包装器
   */
  private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
    ResultSet rs = null;
    SQLException e1 = null;

    try {
      rs = stmt.getResultSet();
    } catch (SQLException e) {
      // Oracle throws ORA-17283 for implicit cursor
      e1 = e;
    }

    try {
      while (rs == null) {
        // move forward to get the first resultSet in case the driver
        // doesn't return the resultSet as the first result (HSQLDB)
        if (stmt.getMoreResults()) {
          rs = stmt.getResultSet();
        } else if (stmt.getUpdateCount() == -1) {
          // no more results. Must be no resultSet
          break;
        }
      }
    } catch (SQLException e) {
      throw e1 != null ? e1 : e;
    }

    return rs != null ? new ResultSetWrapper(rs, configuration) : null;
  }

  /**
   * 获取下一个结果集包装器
   */
  private ResultSetWrapper getNextResultSet(Statement stmt) {
    // Making this method tolerant of bad JDBC drivers
    try {
      // We stopped checking DatabaseMetaData#supportsMultipleResultSets()
      // because Oracle driver (incorrectly) returns false

      // Crazy Standard JDBC way of determining if there are more results
      // DO NOT try to 'improve' the condition even if IDE tells you to!
      // It's important that getUpdateCount() is called here.
      if (!(!stmt.getMoreResults() && stmt.getUpdateCount() == -1)) {
        ResultSet rs = stmt.getResultSet();
        if (rs == null) {
          return getNextResultSet(stmt);
        } else {
          return new ResultSetWrapper(rs, configuration);
        }
      }
    } catch (Exception e) {
      // Intentionally ignored.
    }
    return null;
  }

  /**
   * 关闭结果集资源
   */
  private void closeResultSet(ResultSet rs) {
    try {
      if (rs != null) {
        rs.close();
      }
    } catch (SQLException e) {
      // ignore
    }
  }

  /**
   * 清理处理完一个结果集后的状态
   */
  private void cleanUpAfterHandlingResultSet() {
    nestedResultObjects.clear();
  }

  /**
   * 验证结果映射数量是否合法
   */
  private void validateResultMapsCount(ResultSetWrapper rsw, int resultMapCount) {
    if (rsw != null && resultMapCount < 1) {
      throw new ExecutorException(
          "A query was run and no Result Maps were found for the Mapped Statement '" + mappedStatement.getId()
              + "'. 'resultType' or 'resultMap' must be specified when there is no corresponding method.");
    }
  }

  /**
   * 处理单个结果集,并根据是否有父映射决定如何处理结果
   */
  private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults,
      ResultMapping parentMapping) throws SQLException {
    try {
      if (parentMapping != null) {
        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
      } else if (resultHandler == null) {
        DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
        handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
        multipleResults.add(defaultResultHandler.getResultList());
      } else {
        handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
      }
    } finally {
      closeResultSet(rsw.getResultSet()); // 关闭当前结果集资源
    }
  }

  /**
   * 如果只有一个结果,则返回其本身;否则返回整个列表
   */
  @SuppressWarnings("unchecked")
  private List<Object> collapseSingleResultList(List<Object> multipleResults) {
    return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults;
  }

  /**
   * 处理每一行记录的数据映射工作,区分简单结果映射与嵌套结果映射两种情况
   */
  public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler,
      RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    if (resultMap.hasNestedResultMaps()) {
      ensureNoRowBounds(); // 检查是否启用了安全边界检查模式
      checkResultHandler(); // 检查自定义结果处理器兼容性
      handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    } else {
      handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    }
  }

  /**
   * 确保没有设置不安全的RowBounds限制条件
   */
  private void ensureNoRowBounds() {
    if (configuration.isSafeRowBoundsEnabled() && rowBounds != null
        && (rowBounds.getLimit() < RowBounds.NO_ROW_LIMIT || rowBounds.getOffset() > RowBounds.NO_ROW_OFFSET)) {
      throw new ExecutorException(
          "Mapped Statements with nested result mappings cannot be safely constrained by RowBounds. "
              + "Use safeRowBoundsEnabled=false setting to bypass this check.");
    }
  }

  /**
   * 检查自定义结果处理器是否满足安全要求
   */
  protected void checkResultHandler() {
    if (resultHandler != null && configuration.isSafeResultHandlerEnabled() && !mappedStatement.isResultOrdered()) {
      throw new ExecutorException(
          "Mapped Statements with nested result mappings cannot be safely used with a custom ResultHandler. "
              + "Use safeResultHandlerEnabled=false setting to bypass this check "
              + "or ensure your statement returns ordered data and set resultOrdered=true on it.");
    }
  }

  /**
   * 处理简单的结果映射逻辑(非嵌套结构)
   */
  private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap,
      ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    final boolean useCollectionConstructorInjection = resultMap.hasResultMapsUsingConstructorCollection();

    DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
    ResultSet resultSet = rsw.getResultSet();
    skipRows(resultSet, rowBounds); // 跳过指定偏移量的记录数
    while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw, resultMap, null);
      Object rowValue = getRowValue(rsw, discriminatedResultMap, null, null);
      if (!useCollectionConstructorInjection) {
        storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
      } else {
        if (!(rowValue instanceof PendingConstructorCreation)) {
          throw new ExecutorException("Expected result object to be a pending constructor creation!");
        }

        createAndStorePendingCreation(resultHandler, resultSet, resultContext, (PendingConstructorCreation) rowValue);
      }
    }
  }

  /**
   * 存储处理好的行对象至结果处理器或链接到父对象上
   */
  private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue,
      ResultMapping parentMapping, ResultSet rs) throws SQLException {
    if (parentMapping != null) {
      linkToParents(rs, parentMapping, rowValue);
      return;
    }

    if (pendingPccRelations.containsKey(rowValue)) {
      createPendingConstructorCreations(rowValue);
    }

    callResultHandler(resultHandler, resultContext, rowValue);
  }

  /**
   * 将结果传递给结果处理器进行后续处理
   */
  @SuppressWarnings("unchecked" /* because ResultHandler<?> is always ResultHandler<Object> */)
  private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext,
      Object rowValue) {
    resultContext.nextResultObject(rowValue);
    ((ResultHandler<Object>) resultHandler).handleResult(resultContext);
  }

  /**
   * 判断是否继续处理更多行记录
   */
  private boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) {
    return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
  }

  /**
   * 根据偏移量跳过若干条记录
   */
  private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {
    if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
      if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
        rs.absolute(rowBounds.getOffset());
      }
    } else {
      for (int i = 0; i < rowBounds.getOffset(); i++) {
        if (!rs.next()) {
          break;
        }
      }
    }
  }

  /**
   * 获取简单结果映射对应的一行数据值
   */
  private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix, CacheKey parentRowKey)
      throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix, parentRowKey);
    if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      boolean foundValues = this.useConstructorMappings;
      if (shouldApplyAutomaticMappings(resultMap, false)) {
        foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
      }
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
      foundValues = lazyLoader.size() > 0 || foundValues;
      rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }

    if (parentRowKey != null) {
      // found a simple object/primitive in pending constructor creation that will need linking later
      final CacheKey rowKey = createRowKey(resultMap, rsw, columnPrefix);
      final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);

      if (combinedKey != CacheKey.NULL_CACHE_KEY) {
        nestedResultObjects.put(combinedKey, rowValue);
      }
    }

    return rowValue;
  }

  /**
   * 获取嵌套结果映射对应的一行数据值
   */
  private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, String columnPrefix,
      Object partialObject) throws SQLException {
    final String resultMapId = resultMap.getId();
    Object rowValue = partialObject;
    if (rowValue != null) {
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      putAncestor(rowValue, resultMapId);
      applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
      ancestorObjects.remove(resultMapId);
    } else {
      final ResultLoaderMap lazyLoader = new ResultLoaderMap();
      rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix, combinedKey);
      if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
        final MetaObject metaObject = configuration.newMetaObject(rowValue);
        boolean foundValues = this.useConstructorMappings;
        if (shouldApplyAutomaticMappings(resultMap, true)) {
          foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
        }
        foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
        putAncestor(rowValue, resultMapId);
        foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true)
            || foundValues;
        ancestorObjects.remove(resultMapId);
        foundValues = lazyLoader.size() > 0 || foundValues;
        rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
      }
      if (combinedKey != CacheKey.NULL_CACHE_KEY) {
        nestedResultObjects.put(combinedKey, rowValue);
      }
    }
    return rowValue;
  }

  /**
   * 将祖先对象放入缓存以防止循环引用
   */
  private void putAncestor(Object resultObject, String resultMapId) {
    ancestorObjects.put(resultMapId, resultObject);
  }

  /**
   * 判断是否应该应用自动映射规则
   */
  private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {
    if (resultMap.getAutoMapping() != null) {
      return resultMap.getAutoMapping();
    }
    if (isNested) {
      return AutoMappingBehavior.FULL == configuration.getAutoMappingBehavior();
    } else {
      return AutoMappingBehavior.NONE != configuration.getAutoMappingBehavior();
    }
  }

  /**
   * 应用显式的属性映射规则
   */
  private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
      ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    final Set<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
    boolean foundValues = false;
    final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
    for (ResultMapping propertyMapping : propertyMappings) {
      String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      if (propertyMapping.getNestedResultMapId() != null && !JdbcType.CURSOR.equals(propertyMapping.getJdbcType())) {
        // the user added a column attribute to a nested result map, ignore it
        column = null;
      }
      if (propertyMapping.isCompositeResult()
          || column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))
          || propertyMapping.getResultSet() != null) {
        Object value = getPropertyMappingValue(rsw, metaObject, propertyMapping, lazyLoader, columnPrefix);
        // issue #541 make property optional
        final String property = propertyMapping.getProperty();
        if (property == null) {
          continue;
        }
        if (value == DEFERRED) {
          foundValues = true;
          continue;
        }
        if (value != null) {
          foundValues = true;
        }
        if (value != null
            || configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive()) {
          // gcode issue #377, call setter on nulls (value is not 'found')
          metaObject.setValue(property, value);
        }
      }
    }
    return foundValues;
  }

  /**
   * 获取某个具体属性映射的值
   */
  private Object getPropertyMappingValue(ResultSetWrapper rsw, MetaObject metaResultObject,
      ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    final ResultSet rs = rsw.getResultSet();
    if (propertyMapping.getNestedQueryId() != null) {
      return getNestedQueryMappingValue(rsw, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
    }
    if (JdbcType.CURSOR.equals(propertyMapping.getJdbcType())) {
      List<Object> results = getNestedCursorValue(rsw, propertyMapping, columnPrefix);
      linkObjects(metaResultObject, propertyMapping, results.get(0), true);
      return metaResultObject.getValue(propertyMapping.getProperty());
    }
    if (propertyMapping.getResultSet() != null) {
      addPendingChildRelation(rs, metaResultObject, propertyMapping); // TODO is that OK?
      return DEFERRED;
    } else {
      final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
      if (typeHandler == null) {
        final String property = propertyMapping.getProperty();
        final Type javaType = property == null ? null : metaResultObject.getGenericSetterType(property).getKey();
        typeHandler = rsw.getTypeHandler(javaType, column);
        if (typeHandler == null) {
          throw new ExecutorException(
              "No type handler found for '" + javaType + "' and JDBC type '" + rsw.getJdbcType(column) + "'");
        }
      }
      return typeHandler.getResult(rs, column);
    }
  }

  /**
   * 创建自动映射列表
   */
  private List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap,
      MetaObject metaObject, String columnPrefix) throws SQLException {
    final String mapKey = resultMap.getId() + ":" + columnPrefix;
    List<UnMappedColumnAutoMapping> autoMapping = autoMappingsCache.get(mapKey);
    if (autoMapping == null) {
      autoMapping = new ArrayList<>();
      final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
      // Remove the entry to release the memory
      List<String> mappedInConstructorAutoMapping = constructorAutoMappingColumns.remove(mapKey);
      if (mappedInConstructorAutoMapping != null) {
        unmappedColumnNames.removeAll(mappedInConstructorAutoMapping);
      }
      for (String columnName : unmappedColumnNames) {
        String propertyName = columnName;
        if (columnPrefix != null && !columnPrefix.isEmpty()) {
          // When columnPrefix is specified,
          // ignore columns without the prefix.
          if (!columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
            continue;
          }
          propertyName = columnName.substring(columnPrefix.length());
        }
        final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
        if (property != null && metaObject.hasSetter(property)) {
          if (resultMap.getMappedProperties().contains(property)) {
            continue;
          }
          final Type propertyType = metaObject.getGenericSetterType(property).getKey();
          TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
          if (typeHandler != null) {
            autoMapping.add(new UnMappedColumnAutoMapping(columnName, property, typeHandler,
                propertyType instanceof Class && ((Class<?>) propertyType).isPrimitive()));
          } else {
            configuration.getAutoMappingUnknownColumnBehavior().doAction(mappedStatement, columnName, property,
                propertyType);
          }
        } else {
          configuration.getAutoMappingUnknownColumnBehavior().doAction(mappedStatement, columnName,
              property != null ? property : propertyName, null);
        }
      }
      autoMappingsCache.put(mapKey, autoMapping);
    }
    return autoMapping;
  }

  /**
   * 应用自动映射规则填充对象属性
   */
  private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
      String columnPrefix) throws SQLException {
    List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
    boolean foundValues = false;
    if (!autoMapping.isEmpty()) {
      for (UnMappedColumnAutoMapping mapping : autoMapping) {
        final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
        if (value != null) {
          foundValues = true;
        }
        if (value != null || configuration.isCallSettersOnNulls() && !mapping.primitive) {
          // gcode issue #377, call setter on nulls (value is not 'found')
          metaObject.setValue(mapping.property, value);
        }
      }
    }
    return foundValues;
  }

  /**
   * 连接到父级对象
   */
  private void linkToParents(ResultSet rs, ResultMapping parentMapping, Object rowValue) throws SQLException {
    CacheKey parentKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(),
        parentMapping.getForeignColumn());
    List<PendingRelation> parents = pendingRelations.get(parentKey);
    if (parents != null) {
      for (PendingRelation parent : parents) {
        if (parent != null && rowValue != null) {
          linkObjects(parent.metaObject, parent.propertyMapping, rowValue);
        }
      }
    }
  }

  /**
   * 添加待处理子关系映射
   */
  private void addPendingChildRelation(ResultSet rs, MetaObject metaResultObject, ResultMapping parentMapping)
      throws SQLException {
    CacheKey cacheKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(),
        parentMapping.getColumn());
    PendingRelation deferLoad = new PendingRelation();
    deferLoad.metaObject = metaResultObject;
    deferLoad.propertyMapping = parentMapping;
    List<PendingRelation> relations = pendingRelations.computeIfAbsent(cacheKey, k -> new ArrayList<>());
    // issue #255
    relations.add(deferLoad);
    ResultMapping previous = nextResultMaps.get(parentMapping.getResultSet());
    if (previous == null) {
      nextResultMaps.put(parentMapping.getResultSet(), parentMapping);
    } else if (!previous.equals(parentMapping)) {
      throw new ExecutorException("Two different properties are mapped to the same resultSet");
    }
  }

  /**
   * 创建多结果集关联键
   */
  private CacheKey createKeyForMultipleResults(ResultSet rs, ResultMapping resultMapping, String names, String columns)
      throws SQLException {
    CacheKey cacheKey = new CacheKey();
    cacheKey.update(resultMapping);
    if (columns != null && names != null) {
      String[] columnsArray = columns.split(",");
      String[] namesArray = names.split(",");
      for (int i = 0; i < columnsArray.length; i++) {
        Object value = rs.getString(columnsArray[i]);
        if (value != null) {
          cacheKey.update(namesArray[i]);
          cacheKey.update(value);
        }
      }
    }
    return cacheKey;
  }

  /**
   * 创建结果对象实例
   */
  private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader,
      String columnPrefix, CacheKey parentRowKey) throws SQLException {
    this.useConstructorMappings = false; // reset previous mapping result
    final List<Class<?>> constructorArgTypes = new ArrayList<>();
    final List<Object> constructorArgs = new ArrayList<>();

    Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix,
        parentRowKey);
    if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
      for (ResultMapping propertyMapping : propertyMappings) {
        // issue gcode #109 && issue #149
        if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
          resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration,
              objectFactory, constructorArgTypes, constructorArgs);
          break;
        }
      }

      // (issue #101)
      if (resultMap.hasResultMapsUsingConstructorCollection() && resultObject instanceof PendingConstructorCreation) {
        linkNestedPendingCreations(rsw, resultMap, columnPrefix, parentRowKey,
            (PendingConstructorCreation) resultObject, constructorArgs);
      }
    }

    this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping result
    return resultObject;
  }

  /**
   * 根据不同策略创建结果对象实例
   */
  private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes,
      List<Object> constructorArgs, String columnPrefix, CacheKey parentRowKey) throws SQLException {

    final Class<?> resultType = resultMap.getType();
    final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
    final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
    if (hasTypeHandlerForResultObject(rsw, resultType)) {
      return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
    }
    if (!constructorMappings.isEmpty()) {
      return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs,
          columnPrefix, resultMap.hasResultMapsUsingConstructorCollection(), parentRowKey);
    } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
      return objectFactory.create(resultType);
    } else if (shouldApplyAutomaticMappings(resultMap, false)) {
      return createByConstructorSignature(rsw, resultMap, columnPrefix, resultType, constructorArgTypes,
          constructorArgs);
    }
    throw new ExecutorException("Do not know how to create an instance of " + resultType);
  }

  /**
   * 创建带参数化构造函数的对象实例
   */
  Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType,
      List<ResultMapping> constructorMappings, List<Class<?>> constructorArgTypes, List<Object> constructorArgs,
      String columnPrefix, boolean useCollectionConstructorInjection, CacheKey parentRowKey) {
    boolean foundValues = false;

    for (ResultMapping constructorMapping : constructorMappings) {
      final Class<?> parameterType = constructorMapping.getJavaType();
      final String column = constructorMapping.getColumn();
      final Object value;
      try {
        if (constructorMapping.getNestedQueryId() != null) {
          value = getNestedQueryConstructorValue(rsw, constructorMapping, columnPrefix);
        } else if (JdbcType.CURSOR.equals(constructorMapping.getJdbcType())) {
          List<?> result = (List<?>) getNestedCursorValue(rsw, constructorMapping, columnPrefix).get(0);
          if (objectFactory.isCollection(parameterType)) {
            MetaObject collection = configuration.newMetaObject(objectFactory.create(parameterType));
            collection.addAll((List<?>) result);
            value = collection.getOriginalObject();
          } else {
            value = toSingleObj(result);
          }
        } else if (constructorMapping.getNestedResultMapId() != null) {
          final String constructorColumnPrefix = getColumnPrefix(columnPrefix, constructorMapping);
          final ResultMap resultMap = resolveDiscriminatedResultMap(rsw,
              configuration.getResultMap(constructorMapping.getNestedResultMapId()), constructorColumnPrefix);
          value = getRowValue(rsw, resultMap, constructorColumnPrefix,
              useCollectionConstructorInjection ? parentRowKey : null);
        } else {
          TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
          if (typeHandler == null) {
            typeHandler = typeHandlerRegistry.getTypeHandler(constructorMapping.getJavaType(), rsw.getJdbcType(column));
          }
          value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));
        }
      } catch (ResultMapException | SQLException e) {
        throw new ExecutorException("Could not process result for mapping: " + constructorMapping, e);
      }

      constructorArgTypes.add(parameterType);
      constructorArgs.add(value);

      foundValues = value != null || foundValues;
    }

    if (!foundValues) {
      return null;
    }

    if (useCollectionConstructorInjection) {
      // at least one of the nestedResultMaps contained a collection, we have to defer until later
      return new PendingConstructorCreation(resultType, constructorArgTypes, constructorArgs);
    }

    return objectFactory.create(resultType, constructorArgTypes, constructorArgs);
  }

  /**
   * 使用构造函数签名进行自动映射创建对象实例
   */
  private Object createByConstructorSignature(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix,
      Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) throws SQLException {
    return applyConstructorAutomapping(rsw, resultMap, columnPrefix, resultType, constructorArgTypes, constructorArgs,
        findConstructorForAutomapping(resultType, rsw).orElseThrow(() -> new ExecutorException(
            "No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames())));
  }

  /**
   * 查找适合自动映射的构造函数
   */
  private Optional<Constructor<?>> findConstructorForAutomapping(final Class<?> resultType, ResultSetWrapper rsw) {
    Constructor<?>[] constructors = resultType.getDeclaredConstructors();
    if (constructors.length == 1) {
      return Optional.of(constructors[0]);
    }
    Optional<Constructor<?>> annotated = Arrays.stream(constructors)
        .filter(x -> x.isAnnotationPresent(AutomapConstructor.class)).reduce((x, y) -> {
          throw new ExecutorException("@AutomapConstructor should be used in only one constructor.");
        });
    if (annotated.isPresent()) {
      return annotated;
    }
    if (configuration.isArgNameBasedConstructorAutoMapping()) {
      // Finding-best-match type implementation is possible,
      // but using @AutomapConstructor seems sufficient.
      throw new ExecutorException(MessageFormat.format(
          "'argNameBasedConstructorAutoMapping' is enabled and the class ''{0}'' has multiple constructors, so @AutomapConstructor must be added to one of the constructors.",
          resultType.getName()));
    } else {
      return Arrays.stream(constructors).filter(x -> findUsableConstructorByArgTypes(x, rsw.getJdbcTypes())).findAny();
    }
  }

  /**
   * 判断构造函数参数类型是否匹配JDBC类型
   */
  private boolean findUsableConstructorByArgTypes(final Constructor<?> constructor, final List<JdbcType> jdbcTypes) {
    final Class<?>[] parameterTypes = constructor.getParameterTypes();
    if (parameterTypes.length != jdbcTypes.size()) {
      return false;
    }
    for (int i = 0; i < parameterTypes.length; i++) {
      if (!typeHandlerRegistry.hasTypeHandler(parameterTypes[i], jdbcTypes.get(i))) {
        return false;
      }
    }
    return true;
  }

  /**
   * 应用构造函数自动映射创建对象实例
   */
  private Object applyConstructorAutomapping(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix,
      Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor)
      throws SQLException {
    boolean foundValues = false;
    if (configuration.isArgNameBasedConstructorAutoMapping()) {
      foundValues = applyArgNameBasedConstructorAutoMapping(rsw, resultMap, columnPrefix, constructorArgTypes,
          constructorArgs, constructor, foundValues);
    } else {
      foundValues = applyColumnOrderBasedConstructorAutomapping(rsw, constructorArgTypes, constructorArgs, constructor,
          foundValues);
    }
    return foundValues || configuration.isReturnInstanceForEmptyRow()
        ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
  }

  /**
   * 基于列顺序的构造函数自动映射应用
   */
  private boolean applyColumnOrderBasedConstructorAutomapping(ResultSetWrapper rsw, List<Class<?>> constructorArgTypes,
      List<Object> constructorArgs, Constructor<?> constructor, boolean foundValues) throws SQLException {
    Class<?>[] parameterTypes = constructor.getParameterTypes();

    if (parameterTypes.length > rsw.getClassNames().size()) {
      throw new ExecutorException(MessageFormat.format(
          "Constructor auto-mapping of ''{0}'' failed. The constructor takes ''{1}'' arguments, but there are only ''{2}'' columns in the result set.",
          constructor, parameterTypes.length, rsw.getClassNames().size()));
    }

    for (int i = 0; i < parameterTypes.length; i++) {
      Class<?> parameterType = parameterTypes[i];
      String columnName = rsw.getColumnNames().get(i);
      TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName);
      Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
      constructorArgTypes.add(parameterType);
      constructorArgs.add(value);
      foundValues = value != null || foundValues;
    }
    return foundValues;
  }

  /**
   * 基于参数名称的构造函数自动映射应用
   */
  private boolean applyArgNameBasedConstructorAutoMapping(ResultSetWrapper rsw, ResultMap resultMap,
      String columnPrefix, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor,
      boolean foundValues) throws SQLException {
    List<String> missingArgs = null;
    Parameter[] params = constructor.getParameters();
    for (Parameter param : params) {
      boolean columnNotFound = true;
      Param paramAnno = param.getAnnotation(Param.class);
      String paramName = paramAnno == null ? param.getName() : paramAnno.value();
      for (String columnName : rsw.getColumnNames()) {
        if (columnMatchesParam(columnName, paramName, columnPrefix)) {
          Class<?> paramType = param.getType();
          TypeHandler<?> typeHandler = rsw.getTypeHandler(paramType, columnName);
          Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
          constructorArgTypes.add(paramType);
          constructorArgs.add(value);
          final String mapKey = resultMap.getId() + ":" + columnPrefix;
          if (!autoMappingsCache.containsKey(mapKey)) {
            constructorAutoMappingColumns.computeIfAbsent(mapKey, k -> new ArrayList<>()).add(columnName);
          }
          columnNotFound = false;
          foundValues = value != null || foundValues;
        }
      }
      if (columnNotFound) {
        if (missingArgs == null) {
          missingArgs = new ArrayList<>();
        }
        missingArgs.add(paramName);
      }
    }
    if (foundValues && constructorArgs.size() < params.length) {
      throw new ExecutorException(MessageFormat.format(
          "Constructor auto-mapping of ''{1}'' failed " + "because ''{0}'' were not found in the result set; "
              + "Available columns are ''{2}'' and mapUnderscoreToCamelCase is ''{3}''.",
          missingArgs, constructor, rsw.getColumnNames(), configuration.isMapUnderscoreToCamelCase()));
    }
    return foundValues;
  }

  /**
   * 判断列名是否匹配参数名
   */
  private boolean columnMatchesParam(String columnName, String paramName, String columnPrefix) {
    if (columnPrefix != null) {
      if (!columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
        return false;
      }
      columnName = columnName.substring(columnPrefix.length());
    }
    return paramName
        .equalsIgnoreCase(configuration.isMapUnderscoreToCamelCase() ? columnName.replace("_", "") : columnName);
  }

  /**
   * 创建原始类型结果对象
   */
  private Object createPrimitiveResultObject(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix)
      throws SQLException {
    final Class<?> resultType = resultMap.getType();
    final String columnName;
    if (!resultMap.getResultMappings().isEmpty()) {
      final List<ResultMapping> resultMappingList = resultMap.getResultMappings();
      final ResultMapping mapping = resultMappingList.get(0);
      columnName = prependPrefix(mapping.getColumn(), columnPrefix);
    } else {
      columnName = rsw.getColumnNames().get(0);
    }
    final TypeHandler<?> typeHandler = rsw.getTypeHandler(resultType, columnName);
    return typeHandler.getResult(rsw.getResultSet(), columnName);
  }

  /**
   * 获取嵌套查询构造函数值
   */
  private Object getNestedQueryConstructorValue(ResultSetWrapper rsw, ResultMapping constructorMapping,
      String columnPrefix) throws SQLException {
    final String nestedQueryId = constructorMapping.getNestedQueryId();
    final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
    final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
    final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rsw, constructorMapping,
        nestedQueryParameterType, columnPrefix);
    Object value = null;
    if (nestedQueryParameterObject != null) {
      final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
      final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT,
          nestedBoundSql);
      final Class<?> targetType = constructorMapping.getJavaType();
      final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery,
          nestedQueryParameterObject, targetType, key, nestedBoundSql);
      value = resultLoader.loadResult();
    }
    return value;
  }

  /**
   * 获取嵌套查询映射值
   */
  private Object getNestedQueryMappingValue(ResultSetWrapper rsw, MetaObject metaResultObject,
      ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    final String nestedQueryId = propertyMapping.getNestedQueryId();
    final String property = propertyMapping.getProperty();
    final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
    final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
    final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rsw, propertyMapping,
        nestedQueryParameterType, columnPrefix);
    Object value = null;
    if (nestedQueryParameterObject != null) {
      final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
      final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT,
          nestedBoundSql);
      final Class<?> targetType = propertyMapping.getJavaType();
      if (executor.isCached(nestedQuery, key)) {
        executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType);
        value = DEFERRED;
      } else {
        final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery,
            nestedQueryParameterObject, targetType, key, nestedBoundSql);
        if (propertyMapping.isLazy()) {
          lazyLoader.addLoader(property, metaResultObject, resultLoader);
          value = DEFERRED;
        } else {
          value = resultLoader.loadResult();
        }
      }
    }
    return value;
  }

  /**
   * 准备嵌套查询参数
   */
  private Object prepareParameterForNestedQuery(ResultSetWrapper rsw, ResultMapping resultMapping,
      Class<?> parameterType, String columnPrefix) throws SQLException {
    if (resultMapping.isCompositeResult()) {
      return prepareCompositeKeyParameter(rsw, resultMapping, parameterType, columnPrefix);
    }
    return prepareSimpleKeyParameter(rsw, resultMapping, parameterType, columnPrefix);
  }

  /**
   * 准备简单键参数
   */
  private Object prepareSimpleKeyParameter(ResultSetWrapper rsw, ResultMapping resultMapping, Class<?> parameterType,
      String columnPrefix) throws SQLException {
    // parameterType is ignored in this case
    final String columnName = prependPrefix(resultMapping.getColumn(), columnPrefix);
    final TypeHandler<?> typeHandler = rsw.getTypeHandler(null, columnName);
    return typeHandler.getResult(rsw.getResultSet(), columnName);
  }

  /**
   * 准备复合键参数
   */
  private Object prepareCompositeKeyParameter(ResultSetWrapper rsw, ResultMapping resultMapping, Class<?> parameterType,
      String columnPrefix) throws SQLException {
    // Map is used if parameterType is not specified
    final Object parameterObject = instantiateParameterObject(parameterType);
    final MetaObject metaObject = configuration.newMetaObject(parameterObject);
    boolean foundValues = false;
    for (ResultMapping innerResultMapping : resultMapping.getComposites()) {
      final String columnName = prependPrefix(innerResultMapping.getColumn(), columnPrefix);
      final TypeHandler<?> typeHandler = rsw
          .getTypeHandler(metaObject.getGenericSetterType(innerResultMapping.getProperty()).getKey(), columnName);
      final Object propValue = typeHandler.getResult(rsw.getResultSet(), columnName);
      // issue #353 & #560 do not execute nested query if key is null
      if (propValue != null) {
        metaObject.setValue(innerResultMapping.getProperty(), propValue);
        foundValues = true;
      }
    }
    return foundValues ? parameterObject : null;
  }

  /**
   * 实例化参数对象
   */
  private Object instantiateParameterObject(Class<?> parameterType) {
    if (parameterType == null) {
      return new HashMap<>();
    }
    if (ParamMap.class.equals(parameterType)) {
      return new HashMap<>(); // issue #649
    } else {
      return objectFactory.create(parameterType);
    }
  }

  /**
   * 解析鉴别器映射结果图
   */
  public ResultMap resolveDiscriminatedResultMap(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix)
      throws SQLException {
    Set<String> pastDiscriminators = new HashSet<>();
    Discriminator discriminator = resultMap.getDiscriminator();
    while (discriminator != null) {
      final Object value = getDiscriminatorValue(rsw, discriminator, columnPrefix);
      final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));
      if (!configuration.hasResultMap(discriminatedMapId)) {
        break;
      }
      resultMap = configuration.getResultMap(discriminatedMapId);
      Discriminator lastDiscriminator = discriminator;
      discriminator = resultMap.getDiscriminator();
      if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {
        break;
      }
    }
    return resultMap;
  }

  /**
   * 获取鉴别器值
   */
  private Object getDiscriminatorValue(ResultSetWrapper rsw, Discriminator discriminator, String columnPrefix)
      throws SQLException {
    final ResultMapping resultMapping = discriminator.getResultMapping();
    String column = prependPrefix(resultMapping.getColumn(), columnPrefix);
    TypeHandler<?> typeHandler = resultMapping.getTypeHandler();
    if (typeHandler == null) {
      typeHandler = typeHandlerRegistry.getTypeHandler(resultMapping.getJavaType(), rsw.getJdbcType(column));
    }
    return typeHandler.getResult(rsw.getResultSet(), column);
  }

  /**
   * 给列名加上前缀
   */
  private String prependPrefix(String columnName, String prefix) {
    if (columnName == null || columnName.length() == 0 || prefix == null || prefix.length() == 0) {
      return columnName;
    }
    return prefix + columnName;
  }

  /**
   * 处理嵌套结果映射的行值
   */
  private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap,
      ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    final boolean useCollectionConstructorInjection = resultMap.hasResultMapsUsingConstructorCollection();
    PendingConstructorCreation lastHandledCreation = null;
    if (useCollectionConstructorInjection) {
      verifyPendingCreationPreconditions(parentMapping);
    }

    final DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
    ResultSet resultSet = rsw.getResultSet();
    skipRows(resultSet, rowBounds);
    Object rowValue = previousRowValue;

    while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
      final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw, resultMap, null);
      final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);

      final Object partialObject = nestedResultObjects.get(rowKey);
      final boolean foundNewUniqueRow = partialObject == null;

      // issue #577, #542 && #101
      if (useCollectionConstructorInjection) {
        if (foundNewUniqueRow && lastHandledCreation != null) {
          createAndStorePendingCreation(resultHandler, resultSet, resultContext, lastHandledCreation);
          lastHandledCreation = null;
        }

        rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
        if (rowValue instanceof PendingConstructorCreation) {
          lastHandledCreation = (PendingConstructorCreation) rowValue;
        }
      } else if (mappedStatement.isResultOrdered()) {
        if (foundNewUniqueRow && rowValue != null) {
          nestedResultObjects.clear();
          storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
        }
        rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
      } else {
        rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
        if (foundNewUniqueRow) {
          storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
        }
      }
    }

    if (useCollectionConstructorInjection && lastHandledCreation != null) {
      createAndStorePendingCreation(resultHandler, resultSet, resultContext, lastHandledCreation);
    } else if (rowValue != null && mappedStatement.isResultOrdered()
        && shouldProcessMoreRows(resultContext, rowBounds)) {
      storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
      previousRowValue = null;
    } else if (rowValue != null) {
      previousRowValue = rowValue;
    }
  }

  /**
   * 链接嵌套待处理创建项
   */
  private void linkNestedPendingCreations(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix,
      CacheKey parentRowKey, PendingConstructorCreation pendingCreation, List<Object> constructorArgs)
      throws SQLException {
    if (parentRowKey == null) {
      // nothing to link, possibly due to simple (non-nested) result map
      return;
    }

    final CacheKey rowKey = createRowKey(resultMap, rsw, columnPrefix);
    final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);

    if (combinedKey != CacheKey.NULL_CACHE_KEY) {
      nestedResultObjects.put(combinedKey, pendingCreation);
    }

    final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
    for (int index = 0; index < constructorMappings.size(); index++) {
      final ResultMapping constructorMapping = constructorMappings.get(index);
      final String nestedResultMapId = constructorMapping.getNestedResultMapId();

      if (nestedResultMapId == null) {
        continue;
      }

      final Class<?> javaType = constructorMapping.getJavaType();
      if (javaType == null || !objectFactory.isCollection(javaType)) {
        continue;
      }

      final String constructorColumnPrefix = getColumnPrefix(columnPrefix, constructorMapping);
      final ResultMap nestedResultMap = resolveDiscriminatedResultMap(rsw,
          configuration.getResultMap(constructorMapping.getNestedResultMapId()), constructorColumnPrefix);

      final Object actualValue = constructorArgs.get(index);
      final boolean hasValue = actualValue != null;
      final boolean isInnerCreation = actualValue instanceof PendingConstructorCreation;
      final boolean alreadyCreatedCollection = hasValue && objectFactory.isCollection(actualValue.getClass());

      if (!isInnerCreation) {
        final Collection<Object> value = pendingCreation.initializeCollectionForResultMapping(objectFactory,
            nestedResultMap, constructorMapping, index);
        if (!alreadyCreatedCollection) {
          // override values with empty collection
          constructorArgs.set(index, value);
        }

        // since we are linking a new value, we need to let nested objects know we did that
        final CacheKey nestedRowKey = createRowKey(nestedResultMap, rsw, constructorColumnPrefix);
        final CacheKey nestedCombinedKey = combineKeys(nestedRowKey, combinedKey);

        if (nestedCombinedKey != CacheKey.NULL_CACHE_KEY) {
          nestedResultObjects.put(nestedCombinedKey, pendingCreation);
        }

        if (hasValue) {
          pendingCreation.linkCollectionValue(constructorMapping, actualValue);
        }
      } else {
        final PendingConstructorCreation innerCreation = (PendingConstructorCreation) actualValue;
        final Collection<Object> value = pendingCreation.initializeCollectionForResultMapping(objectFactory,
            nestedResultMap, constructorMapping, index);
        // we will fill this collection when building the final object
        constructorArgs.set(index, value);
        // link the creation for building later
        pendingCreation.linkCreation(constructorMapping, innerCreation);
      }
    }
  }

  /**
   * 应用嵌套待处理构造创建项
   */
  private boolean applyNestedPendingConstructorCreations(ResultSetWrapper rsw, ResultMap resultMap,
      MetaObject metaObject, String parentPrefix, CacheKey parentRowKey, boolean newObject, boolean foundValues) {
    if (newObject) {
      // new objects are linked by createResultObject
      return false;
    }

    for (ResultMapping constructorMapping : resultMap.getConstructorResultMappings()) {
      final String nestedResultMapId = constructorMapping.getNestedResultMapId();
      final Class<?> parameterType = constructorMapping.getJavaType();
      if (nestedResultMapId == null || constructorMapping.getResultSet() != null || parameterType == null
          || !objectFactory.isCollection(parameterType)) {
        continue;
      }

      try {
        final String columnPrefix = getColumnPrefix(parentPrefix, constructorMapping);
        final ResultMap nestedResultMap = getNestedResultMap(rsw, nestedResultMapId, columnPrefix);

        final CacheKey rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
        final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);

        // should have inserted already as a nested result object
        Object rowValue = nestedResultObjects.get(combinedKey);

        PendingConstructorCreation pendingConstructorCreation = null;
        if (rowValue instanceof PendingConstructorCreation) {
          pendingConstructorCreation = (PendingConstructorCreation) rowValue;
        } else if (rowValue != null) {
          // found a simple object that was already linked/handled
          continue;
        }

        final boolean newValueForNestedResultMap = pendingConstructorCreation == null;
        if (newValueForNestedResultMap) {
          final Object parentObject = metaObject.getOriginalObject();
          if (!(parentObject instanceof PendingConstructorCreation)) {
            throw new ExecutorException(
                "parentObject is not a pending creation, cannot continue linking! MyBatis internal error!");
          }

          pendingConstructorCreation = (PendingConstructorCreation) parentObject;
        }

        rowValue = getRowValue(rsw, nestedResultMap, combinedKey, columnPrefix,
            newValueForNestedResultMap ? null : pendingConstructorCreation);

        if (rowValue == null) {
          continue;
        }

        if (rowValue instanceof PendingConstructorCreation) {
          if (newValueForNestedResultMap) {
            // we created a brand new pcc. this is a new collection value
            pendingConstructorCreation.linkCreation(constructorMapping, (PendingConstructorCreation) rowValue);
            foundValues = true;
          }
        } else {
          pendingConstructorCreation.linkCollectionValue(constructorMapping, rowValue);
          foundValues = true;

          if (combinedKey != CacheKey.NULL_CACHE_KEY) {
            nestedResultObjects.put(combinedKey, pendingConstructorCreation);
          }
        }
      } catch (SQLException e) {
        throw new ExecutorException("Error getting constructor collection nested result map values for '"
            + constructorMapping.getProperty() + "'.  Cause: " + e, e);
      }
    }

    return foundValues;
  }

  /**
   * 创建待处理构造项
   */
  private void createPendingConstructorCreations(Object rowValue) {
    // handle possible pending creations within this object
    // by now, the property mapping has been completely built, we can reconstruct it
    final PendingRelation pendingRelation = pendingPccRelations.remove(rowValue);
    final MetaObject metaObject = pendingRelation.metaObject;
    final ResultMapping resultMapping = pendingRelation.propertyMapping;

    // get the list to be built
    Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
    if (collectionProperty != null) {
      // we expect pending creations now
      final Collection<Object> pendingCreations = (Collection<Object>) collectionProperty;

      // remove the link to the old collection
      metaObject.setValue(resultMapping.getProperty(), null);

      // create new collection property
      collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
      final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);

      // create the pending objects
      for (Object pendingCreation : pendingCreations) {
        if (pendingCreation instanceof PendingConstructorCreation) {
          final PendingConstructorCreation pendingConstructorCreation = (PendingConstructorCreation) pendingCreation;
          targetMetaObject.add(pendingConstructorCreation.create(objectFactory));
        }
      }
    }
  }

  /**
   * 验证待处理创建的前提条件
   */
  private void verifyPendingCreationPreconditions(ResultMapping parentMapping) {
    if (parentMapping != null) {
      throw new ExecutorException(
          "Cannot construct objects with collections in constructors using multiple result sets yet!");
    }

    if (!mappedStatement.isResultOrdered()) {
      throw new ExecutorException("Cannot reliably construct result if we are not sure the results are ordered "
          + "so that no new previous rows would occur, set resultOrdered on your mapped statement if you have verified this");
    }
  }

  /**
   * 创建并存储待处理创建项
   */
  private void createAndStorePendingCreation(ResultHandler<?> resultHandler, ResultSet resultSet,
      DefaultResultContext<Object> resultContext, PendingConstructorCreation pendingCreation) throws SQLException {
    final Object result = pendingCreation.create(objectFactory);
    storeObject(resultHandler, resultContext, result, null, resultSet);
    nestedResultObjects.clear();
  }

  /**
   * 应用嵌套结果映射
   */
  private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
      String parentPrefix, CacheKey parentRowKey, boolean newObject) {
    boolean foundValues = false;
    for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) {
      final String nestedResultMapId = resultMapping.getNestedResultMapId();
      if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
        try {
          final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);
          final ResultMap nestedResultMap = getNestedResultMap(rsw, nestedResultMapId, columnPrefix);
          if (resultMapping.getColumnPrefix() == null) {
            // try to fill circular reference only when columnPrefix
            // is not specified for the nested result map (issue #215)
            Object ancestorObject = ancestorObjects.get(nestedResultMapId);
            if (ancestorObject != null) {
              if (newObject) {
                linkObjects(metaObject, resultMapping, ancestorObject); // issue #385
              }
              continue;
            }
          }
          final CacheKey rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
          final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
          Object rowValue = nestedResultObjects.get(combinedKey);
          boolean knownValue = rowValue != null;
          instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject); // mandatory
          if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw)) {
            rowValue = getRowValue(rsw, nestedResultMap, combinedKey, columnPrefix, rowValue);
            if (rowValue != null && !knownValue) {
              linkObjects(metaObject, resultMapping, rowValue);
              foundValues = true;
            }
          }
        } catch (SQLException e) {
          throw new ExecutorException(
              "Error getting nested result map values for '" + resultMapping.getProperty() + "'.  Cause: " + e, e);
        }
      }
    }

    // (issue #101)
    if (resultMap.hasResultMapsUsingConstructorCollection()) {
      foundValues = applyNestedPendingConstructorCreations(rsw, resultMap, metaObject, parentPrefix, parentRowKey,
          newObject, foundValues);
    }

    return foundValues;
  }

  /**
   * 获取列前缀
   */
  private String getColumnPrefix(String parentPrefix, ResultMapping resultMapping) {
    final StringBuilder columnPrefixBuilder = new StringBuilder();
    if (parentPrefix != null) {
      columnPrefixBuilder.append(parentPrefix);
    }
    if (resultMapping.getColumnPrefix() != null) {
      columnPrefixBuilder.append(resultMapping.getColumnPrefix());
    }
    return columnPrefixBuilder.length() == 0 ? null : columnPrefixBuilder.toString().toUpperCase(Locale.ENGLISH);
  }

  /**
   * 检查非空列是否存在有效值
   */
  private boolean anyNotNullColumnHasValue(ResultMapping resultMapping, String columnPrefix, ResultSetWrapper rsw)
      throws SQLException {
    Set<String> notNullColumns = resultMapping.getNotNullColumns();
    if (notNullColumns != null && !notNullColumns.isEmpty()) {
      ResultSet rs = rsw.getResultSet();
      for (String column : notNullColumns) {
        rs.getObject(prependPrefix(column, columnPrefix));
        if (!rs.wasNull()) {
          return true;
        }
      }
      return false;
    }
    if (columnPrefix != null) {
      for (String columnName : rsw.getColumnNames()) {
        if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix.toUpperCase(Locale.ENGLISH))) {
          return true;
        }
      }
      return false;
    }
    return true;
  }

  /**
   * 获取嵌套结果映射
   */
  private ResultMap getNestedResultMap(ResultSetWrapper rsw, String nestedResultMapId, String columnPrefix)
      throws SQLException {
    ResultMap nestedResultMap = configuration.getResultMap(nestedResultMapId);
    return resolveDiscriminatedResultMap(rsw, nestedResultMap, columnPrefix);
  }

  /**
   * 创建行键
   */
  private CacheKey createRowKey(ResultMap resultMap, ResultSetWrapper rsw, String columnPrefix) throws SQLException {
    final CacheKey cacheKey = new CacheKey();
    cacheKey.update(resultMap.getId());
    List<ResultMapping> resultMappings = getResultMappingsForRowKey(resultMap);
    if (resultMappings.isEmpty()) {
      if (Map.class.isAssignableFrom(resultMap.getType())) {
        createRowKeyForMap(rsw, cacheKey);
      } else {
        createRowKeyForUnmappedProperties(resultMap, rsw, cacheKey, columnPrefix);
      }
    } else {
      createRowKeyForMappedProperties(resultMap, rsw, cacheKey, resultMappings, columnPrefix);
    }
    if (cacheKey.getUpdateCount() < 2) {
      return CacheKey.NULL_CACHE_KEY;
    }
    return cacheKey;
  }

  /**
   * 合并两个缓存键
   */
  private CacheKey combineKeys(CacheKey rowKey, CacheKey parentRowKey) {
    if (rowKey.getUpdateCount() > 1 && parentRowKey.getUpdateCount() > 1) {
      CacheKey combinedKey;
      try {
        combinedKey = rowKey.clone();
      } catch (CloneNotSupportedException e) {
        throw new ExecutorException("Error cloning cache key.  Cause: " + e, e);
      }
      combinedKey.update(parentRowKey);
      return combinedKey;
    }
    return CacheKey.NULL_CACHE_KEY;
  }

  /**
   * 获取用于创建行键的结果映射
   */
  private List<ResultMapping> getResultMappingsForRowKey(ResultMap resultMap) {
    List<ResultMapping> resultMappings = resultMap.getIdResultMappings();
    if (resultMappings.isEmpty()) {
      resultMappings = resultMap.getPropertyResultMappings();
    }
    return resultMappings;
  }

  /**
   * 为已映射属性创建行键
   */
  private void createRowKeyForMappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey,
      List<ResultMapping> resultMappings, String columnPrefix) throws SQLException {
    for (ResultMapping resultMapping : resultMappings) {
      if (resultMapping.isSimple()) {
        final String column = prependPrefix(resultMapping.getColumn(), columnPrefix);
        TypeHandler<?> th = resultMapping.getTypeHandler();
        Set<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
        // Issue #114
        if (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) {
          if (th == null) {
            th = typeHandlerRegistry.getTypeHandler(rsw.getJdbcType(column));
          }
          if (th == null) {
            th = ObjectTypeHandler.INSTANCE;
          }
          final Object value = th.getResult(rsw.getResultSet(), column);
          if (value != null || configuration.isReturnInstanceForEmptyRow()) {
            cacheKey.update(column);
            cacheKey.update(value);
          }
        }
      }
    }
  }

  /**
   * 为未映射属性创建行键
   */
  private void createRowKeyForUnmappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey,
      String columnPrefix) throws SQLException {
    final MetaClass metaType = MetaClass.forClass(resultMap.getType(), reflectorFactory);
    List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
    for (String column : unmappedColumnNames) {
      String property = column;
      if (columnPrefix != null && !columnPrefix.isEmpty()) {
        // When columnPrefix is specified, ignore columns without the prefix.
        if (!column.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
          continue;
        }
        property = column.substring(columnPrefix.length());
      }
      if (metaType.findProperty(property, configuration.isMapUnderscoreToCamelCase()) != null) {
        String value = rsw.getResultSet().getString(column);
        if (value != null) {
          cacheKey.update(column);
          cacheKey.update(value);
        }
      }
    }
  }

  /**
   * 为Map类型创建行键
   */
  private void createRowKeyForMap(ResultSetWrapper rsw, CacheKey cacheKey) throws SQLException {
    List<String> columnNames = rsw.getColumnNames();
    for (String columnName : columnNames) {
      final String value = rsw.getResultSet().getString(columnName);
      if (value != null) {
        cacheKey.update(columnName);
        cacheKey.update(value);
      }
    }
  }

  /**
   * 连接对象
   */
  private void linkObjects(MetaObject metaObject, ResultMapping resultMapping, Object rowValue) {
    linkObjects(metaObject, resultMapping, rowValue, false);
  }

  /**
   * 连接对象(支持游标结果)
   */
  private void linkObjects(MetaObject metaObject, ResultMapping resultMapping, Object rowValue,
      boolean isNestedCursorResult) {
    final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
    if (collectionProperty != null) {
      final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
      if (isNestedCursorResult) {
        targetMetaObject.addAll((List<?>) rowValue);
      } else {
        targetMetaObject.add(rowValue);
      }

      // it is possible for pending creations to get set via property mappings,
      // keep track of these, so we can rebuild them.
      final Object originalObject = metaObject.getOriginalObject();
      if (rowValue instanceof PendingConstructorCreation && !pendingPccRelations.containsKey(originalObject)) {
        PendingRelation pendingRelation = new PendingRelation();
        pendingRelation.propertyMapping = resultMapping;
        pendingRelation.metaObject = metaObject;

        pendingPccRelations.put(originalObject, pendingRelation);
      }
    } else {
      metaObject.setValue(resultMapping.getProperty(),
          isNestedCursorResult ? toSingleObj((List<?>) rowValue) : rowValue);
    }
  }

  /**
   * 转换为单一对象
   */
  private Object toSingleObj(List<?> list) {
    // Even if there are multiple elements, silently returns the first one.
    return list.isEmpty() ? null : list.get(0);
  }

  /**
   * 适当时实例化集合属性
   */
  private Object instantiateCollectionPropertyIfAppropriate(ResultMapping resultMapping, MetaObject metaObject) {
    final String propertyName = resultMapping.getProperty();
    Object propertyValue = metaObject.getValue(propertyName);
    if (propertyValue == null) {
      Class<?> type = resultMapping.getJavaType();
      if (type == null) {
        type = metaObject.getSetterType(propertyName);
      }
      try {
        if (objectFactory.isCollection(type)) {
          propertyValue = objectFactory.create(type);
          metaObject.setValue(propertyName, propertyValue);
          return propertyValue;
        }
      } catch (Exception e) {
        throw new ExecutorException(
            "Error instantiating collection property for result '" + resultMapping.getProperty() + "'.  Cause: " + e,
            e);
      }
    } else if (objectFactory.isCollection(propertyValue.getClass())) {
      return propertyValue;
    }
    return null;
  }

  /**
   * 检查结果对象是否有类型处理器
   */
  private boolean hasTypeHandlerForResultObject(ResultSetWrapper rsw, Class<?> resultType) {
    if (rsw.getColumnNames().size() == 1) {
      return typeHandlerRegistry.hasTypeHandler(resultType, rsw.getJdbcType(rsw.getColumnNames().get(0)));
    }
    return typeHandlerRegistry.hasTypeHandler(resultType);
  }
}

7 类型转换模块

8 插件机制

参考executor的创建:

java 复制代码
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
        executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
        executor = new ReuseExecutor(this, transaction);
    } else {
        executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
        executor = new CachingExecutor(executor);
    }
    return (Executor) interceptorChain.pluginAll(executor);
}
java 复制代码
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
    target = interceptor.plugin(target);
}
return target;
}
java 复制代码
default Object plugin(Object target) {
    return Plugin.wrap(target, this);
}
java 复制代码
public static Object wrap(Object target, Interceptor interceptor) {
    Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    Class<?> type = target.getClass();
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    if (interfaces.length > 0) {
        return Proxy.newProxyInstance(type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap));
    }
    return target;
}

Plugin类的属性:

java 复制代码
private final Object target;//被代理的对象
private final Interceptor interceptor;//插件
private final Map<Class<?>, Set<Method>> signatureMap;//注解集合
java 复制代码
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
        //获取注解列表
        Set<Method> methods = signatureMap.get(method.getDeclaringClass());
        //执行插件
        if (methods != null && methods.contains(method)) {
            return interceptor.intercept(new Invocation(target, method, args));
        }
        //直接执行被代理对象的方法
        return method.invoke(target, args);
    } catch (Exception e) {
        throw ExceptionUtil.unwrapThrowable(e);
    }
}

配置解析

XMLConfigBuilder:读取xml配置,并扫描mapper文件

Configuration:存储配置信息和MapperRegistry

MapperRegistry:存储所有mapper,每一个mapper class对应一个MapperProxyFactory。

相关推荐
老马95272 小时前
MyBatis-Plus 动态表名的正确打开方式
后端·mybatis
计算机学姐6 小时前
基于SpringBoot的共享单车管理系统【2026最新】
java·spring boot·后端·spring·java-ee·intellij-idea·mybatis
独自破碎E6 小时前
什么是循环依赖
java·mysql·mybatis
用户2190326527356 小时前
能省事”。SpringBoot+MyBatis-Plus:开发效率提升10倍!
java·spring boot·mybatis
雨中飘荡的记忆7 小时前
MyBatis SQL解析模块详解
java·mybatis
undsky7 小时前
【RuoYi-SpringBoot3-Pro】:MyBatis-Plus 集成
spring boot·后端·mybatis
GISERLiu7 小时前
Mapper 怎么能找到实体和数据库
数据库·oracle·mybatis
乐之者v8 小时前
AI生成mybatis代码
java·mybatis