美文网首页orm
MyBatis源码阅读【执行】(八)结果集映射流程

MyBatis源码阅读【执行】(八)结果集映射流程

作者: 云芈山人 | 来源:发表于2021-05-28 23:14 被阅读0次

    入口:DefaultResultSetHandler#handleResultSets

    结果集映射

    @Override
        public List<Object> handleResultSets(Statement stmt) throws SQLException {
            ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
    
            // <select>标签的resultMap属性,可以指定多个值,多个值之间用逗号(,)分割
            final List<Object> multipleResults = new ArrayList<>();
    
            int resultSetCount = 0;
            // 这里是获取第一个结果集,将传统JDBC的ResultSet包装成一个包含结果列元信息的ResultSetWrapper对象
            ResultSetWrapper rsw = getFirstResultSet(stmt);
    
            // 这里是获取所有要映射的ResultMap(按照逗号分割出来的)
            List<ResultMap> resultMaps = mappedStatement.getResultMaps();
            // 要映射的ResultMap的数量
            int resultMapCount = resultMaps.size();
            validateResultMapsCount(rsw, resultMapCount);
            // 循环处理每个ResultMap,从第一个开始处理
            while (rsw != null && resultMapCount > resultSetCount) {
                // 得到结果映射信息
                ResultMap resultMap = resultMaps.get(resultSetCount);
                // 处理结果集
                // 从rsw结果集参数中获取查询结果,再根据resultMap映射信息,将查询结果映射到multipleResults中
                handleResultSet(rsw, resultMap, multipleResults, null);
    
                rsw = getNextResultSet(stmt);
                cleanUpAfterHandlingResultSet();
                resultSetCount++;
            }
    
            // 对应<select>标签的resultSets属性,一般不使用该属性
            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);
        }
    

    流程图

    结果集映射流程.png

    流程分析

    • DefaultResultSetHandler#handleResultSet

      从rsw结果集参数中获取查询结果,再根据resultMap映射信息,将查询结果映射到multipleResults中
    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 {
                    // 第一次一般来说resultHandler为空,则创建DefaultResultHandler来处理结果
                    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 {
                // issue #228 (close resultsets)
                closeResultSet(rsw.getResultSet());
            }
        }
    
    • DefaultResultSetHandler#handleRowValues

      处理行数据,其实就是完成结果映射
    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);
            }
        }
    
    • DefaultResultSetHandler#handleRowValuesForSimpleResultMap

      简单结果映射
    private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap,
                ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
            DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
            // 获取结果集信息
            ResultSet resultSet = rsw.getResultSet();
            // 使用rowBounds的分页信息,进行逻辑分页(也就是在内存中分页)
            skipRows(resultSet, rowBounds);
            while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
                // 通过<resultMap>标签的子标签<discriminator>对结果映射进行鉴别
                ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
                // 将查询结果封装到POJO中
                Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
                // 处理对象嵌套的映射关系
                storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
            }
        }
    
    • 1. DefaultResultSetHandler#getRowValue

      将查询结果封装到POJO中
    private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
            // 延迟加载的映射信息
            final ResultLoaderMap lazyLoader = new ResultLoaderMap();
            // 创建要映射的PO类对象
            Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
            if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
                final MetaObject metaObject = configuration.newMetaObject(rowValue);
                boolean foundValues = this.useConstructorMappings;
                // 是否应用自动映射,也就是通过resultType进行映射
                if (shouldApplyAutomaticMappings(resultMap, false)) {
                    // 根据columnName和type属性名映射赋值
                    foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
                }
                // 根据我们配置ResultMap的column和property映射赋值
                // 如果映射存在nestedQueryId,会调用getNestedQueryMappingValue方法获取返回值
                foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
                foundValues = lazyLoader.size() > 0 || foundValues;
                rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
            }
            return rowValue;
        }
    
    • 1.1 DefaultResultSetHandler#createResultObject

      创建映射结果对象
    private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader,
                String columnPrefix) throws SQLException {
            this.useConstructorMappings = false; // reset previous mapping result
            final List<Class<?>> constructorArgTypes = new ArrayList<>();
            final List<Object> constructorArgs = new ArrayList<>();
            // 创建结果映射的PO类对象
            Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
            if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
                // 获取要映射的PO类的属性信息
                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;
                    }
                }
            }
            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) 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);
            } else if (!constructorMappings.isEmpty()) {
                return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes,
                        constructorArgs, columnPrefix);
            } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
                // 对象工厂创建对象
                return objectFactory.create(resultType);
            } else if (shouldApplyAutomaticMappings(resultMap, false)) {
                return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix);
            }
            throw new ExecutorException("Do not know how to create an instance of " + resultType);
        }
    
    • 1.2 DefaultResultSetHandler#applyAutomaticMappings

      根据columnName和type属性名映射赋值
    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;
        }
    
    • 1.3 DefaultResultSetHandler#applyPropertyMappings

      根据我们配置ResultMap的column和property映射赋值,如果映射存在nestedQueryId,会调用getNestedQueryMappingValue方法获取返回值
    private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
                ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
            final List<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) {
                    // 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.getResultSet(), metaObject, propertyMapping, lazyLoader,
                            columnPrefix);
                    // issue #541 make property optional
                    final String property = propertyMapping.getProperty();
                    if (property == null) {
                        continue;
                    } else 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;
        }
    

    相关文章

      网友评论

        本文标题:MyBatis源码阅读【执行】(八)结果集映射流程

        本文链接:https://www.haomeiwen.com/subject/ffpfsltx.html