• mybatis DefaultResultSetHandler 【逻辑分页源码解析】


    public class DefaultResultSetHandler implements ResultSetHandler {
    
      private static final Object DEFERED = 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;
    
      // nested resultmaps
      private final Map<CacheKey, Object> nestedResultObjects = new HashMap<>();
      private final Map<String, Object> ancestorObjects = new HashMap<>();
      private Object previousRowValue;
    
      // multiple resultsets
      private final Map<String, ResultMapping> nextResultMaps = new HashMap<>();
      private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<>();
    
      // Cached Automappings
      private final Map<String, List<UnMappedColumnAutoMapping>> autoMappingsCache = new HashMap<>();
    
      // temporary marking flag that indicate using constructor mapping (use field to reduce memory usage)
      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;
        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;
      }
    
      //
      // HANDLE OUTPUT PARAMETER
      //
    
      @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 TypeHandler<?> typeHandler = parameterMapping.getTypeHandler();
              metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1));
            }
          }
        }
      }
    
      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 {
          // issue #228 (close resultsets)
          closeResultSet(rs);
        }
      }
    
      //
      // HANDLE RESULT SETS
      //
      @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;
        //statment可能返回多个结果集对象,这里先取出第一个结果集
        ResultSetWrapper rsw = getFirstResultSet(stmt);
        //获取结果集对应resultMap,本质就是获取字段与java属性的映射规则
        List<ResultMap> resultMaps = mappedStatement.getResultMaps();
        int resultMapCount = resultMaps.size();
        validateResultMapsCount(rsw, resultMapCount);//结果集和resultMap不能为空,为空抛出异常
        while (rsw != null && resultMapCount > resultSetCount) {
         //获取当前结果集对应的resultMap
          ResultMap resultMap = resultMaps.get(resultSetCount);
          //根据映射规则(resultMap)对结果集进行转化,转换成目标对象以后放入multipleResults中
          handleResultSet(rsw, resultMap, multipleResults, null);
          rsw = getNextResultSet(stmt);//获取下一个结果集
          cleanUpAfterHandlingResultSet();//清空nestedResultObjects对象
          resultSetCount++;
        }
        //获取多结果集。多结果集一般出现在存储过程的执行,存储过程返回多个resultset,
        //mappedStatement.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);
      }
    
      @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 = stmt.getResultSet();
        while (rs == null) {
          // move forward to get the first resultset in case the driver
          // doesn't return the resultset as the first result (HSQLDB 2.1)
          if (stmt.getMoreResults()) {
            rs = stmt.getResultSet();
          } else {
            if (stmt.getUpdateCount() == -1) {
              // no more results. Must be no resultset
              break;
            }
          }
        }
        return rs != null ? new ResultSetWrapper(rs, configuration) : null;
      }
    
      private ResultSetWrapper getNextResultSet(Statement stmt) {
        // Making this method tolerant of bad JDBC drivers
        try {
          if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {
            // Crazy Standard JDBC way of determining if there are more results
            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()
              + "'.  It's likely that neither a Result Type nor a Result Map was specified.");
        }
      }
    
      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) {//如果resultHandler为空,实例化一个人默认的resultHandler
              DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
              //对ResultSet进行映射,映射结果暂存在resultHandler中
              handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
              //将暂存在resultHandler中的映射结果,填充到multipleResults
              multipleResults.add(defaultResultHandler.getResultList());
            } else {
              //使用指定的rusultHandler进行转换
              handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
            }
          }
        } finally {
          // issue #228 (close resultsets)
          //调用resultset.close()关闭结果集
          closeResultSet(rsw.getResultSet());
        }
      }
    
      @SuppressWarnings("unchecked")
      private List<Object> collapseSingleResultList(List<Object> multipleResults) {
        return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults;
      }
    
      //
      // HANDLE ROWS FOR SIMPLE RESULTMAP
      //
    
      public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
        if (resultMap.hasNestedResultMaps()) {//处理有嵌套resultmap的情况
          ensureNoRowBounds();
          checkResultHandler();
          handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
        } else {//处理没有嵌套resultmap的情况
          handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
        }
      }
    
      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 {
    	//创建结果上下文,所谓的上下文就是专门在循环中缓存结果对象的
        DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
        //1.根据分页信息,定位到指定的记录
        skipRows(rsw.getResultSet(), rowBounds);
        //2.shouldProcessMoreRows判断是否需要映射后续的结果,实际还是翻页处理,避免超过limit
        while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
          //3.进一步完善resultMap信息,主要是处理鉴别器的信息
          ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
          //4.读取resultSet中的一行记录并进行映射,转化并返回目标对象
          Object rowValue = getRowValue(rsw, discriminatedResultMap);
          //5.保存映射结果对象
          storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
        }
      }
    
      //保存映射结果对象
      private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
        if (parentMapping != null) {//如果是嵌套结果或嵌套查询,将对象保存至父对象
          linkToParents(rs, parentMapping, rowValue);
        } else {//普通映射则把对象保存至resultHandler和resultContext
          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) {
    	 //检测上下文的stop状态,并检测映射的行数是否达到了limit的上限
        return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
      }
    
      //映射之前处理翻页信息
      private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {
    	//根据ResultSet的类型定位
        if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
          if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
            rs.absolute(rowBounds.getOffset());//直接定位到offset指定的记录
          }
        } else {
          //通过多次调用next移动到目标记录
          for (int i = 0; i < rowBounds.getOffset(); i++) {
            rs.next();
          }
        }
      }
    
      //
      // GET VALUE FROM ROW FOR SIMPLE RESULT MAP
      //
      //4.读取resultSet中的一行记录并进行映射,转化并返回目标对象
      private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
        final ResultLoaderMap lazyLoader = new ResultLoaderMap();
        //4.1 根据resultMap的type属性,实例化目标对象
        Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);
        if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
          //4.2 对目标对象进行封装得到metaObjcect,为后续的赋值操作做好准备
          final MetaObject metaObject = configuration.newMetaObject(rowValue);
          boolean foundValues = this.useConstructorMappings;//取得是否使用构造函数初始化属性值
          if (shouldApplyAutomaticMappings(resultMap, false)) {//是否使用自动映射
        	 //4.3一般情况下 autoMappingBehavior默认值为PARTIAL,对未明确指定映射规则的字段进行自动映射
            foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
          }
           //4.4 映射resultMap中明确指定需要映射的列
          foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
          foundValues = lazyLoader.size() > 0 || foundValues;
          //4.5 如果没有一个映射成功的属性,则根据<returnInstanceForEmptyRow>的配置返回null或者结果对象
          rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
        }
        return rowValue;
      }
    
      private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {
        if (resultMap.getAutoMapping() != null) {
          return resultMap.getAutoMapping();
        } else {
          if (isNested) {
            return AutoMappingBehavior.FULL == configuration.getAutoMappingBehavior();
          } else {
            return AutoMappingBehavior.NONE != configuration.getAutoMappingBehavior();
          }
        }
      }
    
      //
      // PROPERTY MAPPINGS
      //
    
      private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
          throws SQLException {
    	//从resultMap中获取明确需要转换的列名集合
        final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
        boolean foundValues = false;
        //获取ResultMapping集合
        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
        	//如果属性通过另外一个resultMap映射,则忽略
            column = null;
          }
          if (propertyMapping.isCompositeResult()//如果是嵌套查询,column={prop1=col1,prop2=col2}
              || (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 == DEFERED) {//属性名为DEFERED,延迟加载的处理
              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为目标对象设置属性值
              metaObject.setValue(property, value);
            }
          }
        }
        return foundValues;
      }
      
      //获得属性值
      private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
          throws SQLException {
        if (propertyMapping.getNestedQueryId() != null) {//嵌套查询的处理
          return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
        } else if (propertyMapping.getResultSet() != null) {//嵌套结果的处理
          addPendingChildRelation(rs, metaResultObject, propertyMapping);   // TODO is that OK?
          return DEFERED;
        } else {//基本类型直接通过typeHandler获取属性值
          final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
          final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
          return typeHandler.getResult(rs, column);
        }
      }
      //获取resultSet中存在的,但是ResultMap中没有明确映射的列,填充至autoMapping中
      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);
          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)) {//如果有前缀,属性名为列名去除前缀
                propertyName = columnName.substring(columnPrefix.length());
              } else {
                continue;
              }
            }
            //在结果对象中查找指定的属性名
            final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
            //检查该属性是否有setter方法
            if (property != null && metaObject.hasSetter(property)) {
              if (resultMap.getMappedProperties().contains(property)) {//如果该属性在resultMap中已经指定,则忽略此属性
                continue;
              }
              final Class<?> propertyType = metaObject.getSetterType(property);
              if (typeHandlerRegistry.hasTypeHandler(propertyType, rsw.getJdbcType(columnName))) {//判断是否有匹配的typeHandler
                final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);//找到类型转换器
                //创建UnMappedColumnAutoMapping,并填充至autoMapping
                autoMapping.add(new UnMappedColumnAutoMapping(columnName, property, typeHandler, 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 {
    	//获取resultSet中存在的,但是ResultMap中没有明确映射的列,填充至autoMapping中
        List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
        boolean foundValues = false;
        if (!autoMapping.isEmpty()) {
          //遍历autoMapping,通过自动匹配的方式为属性复制
          for (UnMappedColumnAutoMapping mapping : autoMapping) {
        	//通过typeHandler从resultset中拿值
            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给属性赋值
              metaObject.setValue(mapping.property, value);
            }
          }
        }
        return foundValues;
      }
    
      // MULTIPLE RESULT SETS
    
      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;
      }
    
      //
      // INSTANTIATION & CONSTRUCTOR MAPPING
      //
    
      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<>();
        Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
        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;
            }
          }
        }
        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);
      }
    
      Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType, List<ResultMapping> constructorMappings,
                                             List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) {
        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.getResultSet(), constructorMapping, columnPrefix);
            } else if (constructorMapping.getNestedResultMapId() != null) {
              final ResultMap resultMap = configuration.getResultMap(constructorMapping.getNestedResultMapId());
              value = getRowValue(rsw, resultMap);
            } else {
              final TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
              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;
        }
        return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
      }
    
      private Object createByConstructorSignature(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs,
                                                  String columnPrefix) throws SQLException {
        final Constructor<?>[] constructors = resultType.getDeclaredConstructors();
        final Constructor<?> defaultConstructor = findDefaultConstructor(constructors);
        if (defaultConstructor != null) {
          return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix, defaultConstructor);
        } else {
          for (Constructor<?> constructor : constructors) {
            if (allowedConstructorUsingTypeHandlers(constructor, rsw.getJdbcTypes())) {
              return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix, constructor);
            }
          }
        }
        throw new ExecutorException("No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames());
      }
    
      private Object createUsingConstructor(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix, Constructor<?> constructor) throws SQLException {
        boolean foundValues = false;
        for (int i = 0; i < constructor.getParameterTypes().length; i++) {
          Class<?> parameterType = constructor.getParameterTypes()[i];
          String columnName = rsw.getColumnNames().get(i);
          TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName);
          Object value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(columnName, columnPrefix));
          constructorArgTypes.add(parameterType);
          constructorArgs.add(value);
          foundValues = value != null || foundValues;
        }
        return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
      }
    
      private Constructor<?> findDefaultConstructor(final Constructor<?>[] constructors) {
        if (constructors.length == 1) return constructors[0];
    
        for (final Constructor<?> constructor : constructors) {
          if (constructor.isAnnotationPresent(AutomapConstructor.class)) {
            return constructor;
          }
        }
        return null;
      }
    
      private boolean allowedConstructorUsingTypeHandlers(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 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);
      }
    
      //
      // NESTED QUERY
      //
    
      private Object getNestedQueryConstructorValue(ResultSet rs, 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(rs, 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(ResultSet rs, 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(rs, 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 = DEFERED;
          } else {
            final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
            if (propertyMapping.isLazy()) {
              lazyLoader.addLoader(property, metaResultObject, resultLoader);
              value = DEFERED;
            } else {
              value = resultLoader.loadResult();
            }
          }
        }
        return value;
      }
    
      private Object prepareParameterForNestedQuery(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
        if (resultMapping.isCompositeResult()) {
          return prepareCompositeKeyParameter(rs, resultMapping, parameterType, columnPrefix);
        } else {
          return prepareSimpleKeyParameter(rs, resultMapping, parameterType, columnPrefix);
        }
      }
    
      private Object prepareSimpleKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
        final TypeHandler<?> typeHandler;
        if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
          typeHandler = typeHandlerRegistry.getTypeHandler(parameterType);
        } else {
          typeHandler = typeHandlerRegistry.getUnknownTypeHandler();
        }
        return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
      }
    
      private Object prepareCompositeKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
        final Object parameterObject = instantiateParameterObject(parameterType);
        final MetaObject metaObject = configuration.newMetaObject(parameterObject);
        boolean foundValues = false;
        for (ResultMapping innerResultMapping : resultMapping.getComposites()) {
          final Class<?> propType = metaObject.getSetterType(innerResultMapping.getProperty());
          final TypeHandler<?> typeHandler = typeHandlerRegistry.getTypeHandler(propType);
          final Object propValue = typeHandler.getResult(rs, prependPrefix(innerResultMapping.getColumn(), columnPrefix));
          // 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<>();
        } else if (ParamMap.class.equals(parameterType)) {
          return new HashMap<>(); // issue #649
        } else {
          return objectFactory.create(parameterType);
        }
      }
    
      //
      // DISCRIMINATOR
      //
    
      public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException {
        Set<String> pastDiscriminators = new HashSet<>();
        Discriminator discriminator = resultMap.getDiscriminator();
        while (discriminator != null) {
          final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);
          final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));
          if (configuration.hasResultMap(discriminatedMapId)) {
            resultMap = configuration.getResultMap(discriminatedMapId);
            Discriminator lastDiscriminator = discriminator;
            discriminator = resultMap.getDiscriminator();
            if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {
              break;
            }
          } else {
            break;
          }
        }
        return resultMap;
      }
    
      private Object getDiscriminatorValue(ResultSet rs, Discriminator discriminator, String columnPrefix) throws SQLException {
        final ResultMapping resultMapping = discriminator.getResultMapping();
        final TypeHandler<?> typeHandler = resultMapping.getTypeHandler();
        return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
      }
    
      private String prependPrefix(String columnName, String prefix) {
        if (columnName == null || columnName.length() == 0 || prefix == null || prefix.length() == 0) {
          return columnName;
        }
        return prefix + columnName;
      }
    
      //
      // HANDLE NESTED RESULT MAPS
      //
    
      private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
        final DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
        skipRows(rsw.getResultSet(), rowBounds);
        Object rowValue = previousRowValue;
        while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
          final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
          final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
          Object partialObject = nestedResultObjects.get(rowKey);
          // issue #577 && #542
          if (mappedStatement.isResultOrdered()) {
            if (partialObject == null && rowValue != null) {
              nestedResultObjects.clear();
              storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
            }
            rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
          } else {
            rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
            if (partialObject == null) {
              storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
            }
          }
        }
        if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) {
          storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
          previousRowValue = null;
        } else if (rowValue != null) {
          previousRowValue = rowValue;
        }
      }
    
      //
      // GET VALUE FROM ROW FOR NESTED RESULT MAP
      //
    
      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);
          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);
      }
    
      //
      // NESTED RESULT MAP (JOIN MAPPING)
      //
    
      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.getResultSet(), 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);
            }
          }
        }
        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;
        } else if (columnPrefix != null) {
          for (String columnName : rsw.getColumnNames()) {
            if (columnName.toUpperCase().startsWith(columnPrefix.toUpperCase())) {
              return true;
            }
          }
          return false;
        }
        return true;
      }
    
      private ResultMap getNestedResultMap(ResultSet rs, String nestedResultMapId, String columnPrefix) throws SQLException {
        ResultMap nestedResultMap = configuration.getResultMap(nestedResultMapId);
        return resolveDiscriminatedResultMap(rs, nestedResultMap, columnPrefix);
      }
    
      //
      // UNIQUE RESULT KEY
      //
    
      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.getNestedResultMapId() != null && resultMapping.getResultSet() == null) {
            // Issue #392
            final ResultMap nestedResultMap = configuration.getResultMap(resultMapping.getNestedResultMapId());
            createRowKeyForMappedProperties(nestedResultMap, rsw, cacheKey, nestedResultMap.getConstructorResultMappings(),
                prependPrefix(resultMapping.getColumnPrefix(), columnPrefix));
          } else if (resultMapping.getNestedQueryId() == null) {
            final String column = prependPrefix(resultMapping.getColumn(), columnPrefix);
            final TypeHandler<?> th = resultMapping.getTypeHandler();
            List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
            // Issue #114
            if (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) {
              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)) {
              property = column.substring(columnPrefix.length());
            } else {
              continue;
            }
          }
          if (metaType.findProperty(property, configuration.isMapUnderscoreToCamelCase()) != null) {
            String value = rsw.getResultSet().getString(column);
            if (value != null) {
              cacheKey.update(column);
              cacheKey.update(value);
            }
          }
        }
      }
    
      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) {
        final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
        if (collectionProperty != null) {
          final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
          targetMetaObject.add(rowValue);
        } else {
          metaObject.setValue(resultMapping.getProperty(), rowValue);
        }
      }
    
      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);
      }
    
    }
    

      

    解析 sql 标签的代码;

    查询从表,建议添加前缀

    private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
          throws SQLException {
    	//从resultMap中获取明确需要转换的列名集合
        final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
        boolean foundValues = false;
        //获取ResultMapping集合
        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
        	//如果属性通过另外一个resultMap映射,则忽略
            column = null;
          }
          if (propertyMapping.isCompositeResult()//如果是嵌套查询,column={prop1=col1,prop2=col2}
              || (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 == DEFERED) {//属性名为DEFERED,延迟加载的处理
              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为目标对象设置属性值
              metaObject.setValue(property, value);
            }
          }
        }
        return foundValues;
      }
    

      

  • 相关阅读:
    poj 1226
    在Excel中创建和使用ServerDocument
    Linux进程管理—信号、定时器
    《linux程序设计》--读书笔记--第十四章信号量、共享内存和消息队列
    POJ 1054 The Troublesome Frog
    boost库在工作(37)网络UDP服务端之七
    指纹增强程序Hong_enhancement
    读书笔记——Windows核心编程(15)在应用程序中使用虚拟内存
    蓝牙技术谈之调频技术(一)
    android使用全局变量的两种方法
  • 原文地址:https://www.cnblogs.com/lyr-2000/p/13881721.html
Copyright © 2020-2023  润新知