时序图

Mybatis源码之ResultSet结果集处理_嵌套 Mybatis源码之ResultSet结果集处理_sql_02

详细步骤

PreparedStatementHandler#query

@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    // 执行SQL
    ps.execute();
    // 结果集处理
    return resultSetHandler.handleResultSets(ps);
}

DefaultResultSetHandler#handleResultSets

/**
 * 处理statement得到的多结果集(也可能是单结果集,这是多结果集的一种简化形式),最终得到结果列表
 *
 * handleResultSets 方法完成了对多结果集的处理。但是对于每一个结果集的处理是由handleResultSet子方法实现的
 * @param stmt Statement语句
 * @return 结果列表
 * @throws SQLException
 */
@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);
    // 查询语句对应的resultMap节点,可能含有多个
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    // 合法性校验(存在输出结果集的情况下,resultMapCount不能为0)
    validateResultMapsCount(rsw, resultMapCount);
    // 循环遍历每一个设置了resultMap的结果集
    while (rsw != null && resultMapCount > resultSetCount) {
        // 获得当前结果集对应的ResultMap
        ResultMap resultMap = resultMaps.get(resultSetCount);
        // 进行结果集的处理
        handleResultSet(rsw, resultMap, multipleResults, null);
        // 获取下一结果集
        rsw = getNextResultSet(stmt);
        // 清理上一条结果集的环境
        cleanUpAfterHandlingResultSet();
        resultSetCount++;
    }
    // 获取多结果集中所有结果集的名称
    String[] resultSets = mappedStatement.getResultSets();
    if (resultSets != null) {
        // 循环遍历每一个设置resultMap的结果集
        while (rsw != null && resultSetCount < resultSets.length) {
            // 获取该结果集对应的父级resultMap中的resultMapping(注:resultMapping用来描述对象属性的映射关系)
            ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
            if (parentMapping != null) {
                // 获取被嵌套的resultMap编号
                String nestedResultMapId = parentMapping.getNestedResultMapId();
                ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
                // 处理嵌套映射
                handleResultSet(rsw, resultMap, null, parentMapping);
            }
            rsw = getNextResultSet(stmt);
            cleanUpAfterHandlingResultSet();
            resultSetCount++;
        }
    }
    // 判断是否为单结果集:如果是,则返回结果列表;如果不是则返回结果集列表
    return collapseSingleResultList(multipleResults);
}

DefaultResultSetHandler#handleResultSet

/**
 * 处理单一的结果集
 * @param rsw ResultSet 的包装
 * @param resultMap resultMap节点信息
 * @param multipleResults 用来存储处理结果的列表
 * @param parentMapping
 * @throws SQLException
 */
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
        if (parentMapping != null) { // 嵌套的结果
            // 向子方法闯入parentMapping。处理结果中的记录
            handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
        } else { // 非嵌套的结果
            if (resultHandler == null) {
                // defaultResultHandler 能够将结果对象聚合成一个列表返回
                DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
                // 处理结果中的记录
                handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
                // 添加处理后的结果
                multipleResults.add(defaultResultHandler.getResultList());
            } else {
                handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
            }
        }
    } finally {
        // issue #228 (close resultsets)
        closeResultSet(rsw.getResultSet());
    }
}

DefaultResultSetHandler#handleRowValuesForSimpleResultMap

/**
 * 处理非嵌套映射的结果
 * @param rsw 结果集包装
 * @param resultMap 结果映射
 * @param resultHandler 结果处理器
 * @param rowBounds 翻页限制条件
 * @param parentMapping 父级结果映射
 * @throws SQLException
 */
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
        throws SQLException {
    DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
    // 当前要处理的结果集
    ResultSet resultSet = rsw.getResultSet();
    // 根据翻页配置,跳过指定的行
    skipRows(resultSet, rowBounds);
    // 持续处理下一条结果,判断条件为;还有结果需要处理 && 结果集没有关闭 && 还有下一条结果
    while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
        // 经过鉴别器鉴别,确定经过鉴别器分析的最终要使用resultMap
        ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
        // 拿到一行记录,并且将其转化为一个对象
        Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
        // 把这一行记录转化出的对象存起来
        storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    }
}

DefaultResultSetHandler#getRowValue

  • 解析ResultMap标签时,会将属性的TypeHandler确定下来
/**
 * 将一条记录转化为一个对象
 * @param rsw 结果集包装
 * @param resultMap 结果映射
 * @param columnPrefix 列前缀
 * @return 转化得到的对象
 * @throws SQLException
 */
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    // 创建这一行记录对应的空对象
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
    if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
        // 根据对象得到其MetaObject
        final MetaObject metaObject = configuration.newMetaObject(rowValue);
        boolean foundValues = this.useConstructorMappings;
        // 是否允许自动映射未明示的字段
        if (shouldApplyAutomaticMappings(resultMap, false)) {
            // 自动映射未明示的字段(resultType),映射时的TypeHandler通过属性名与set方法参数类型的映射来获取属性的类型,并据此获取对应的TypeHandler
            foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
        }
        // 按照明示的字段进行重新映射(resultMap),解析XML时获取TypeHandler
        foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
        foundValues = lazyLoader.size() > 0 || foundValues;
        rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    return rowValue;
}

以上便是Mybatis中ResultSet结果集处理流程。