Mybatis源码分析之结果封装ResultSetHandler和DefaultResultSetHandler

Posted 归田

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis源码分析之结果封装ResultSetHandler和DefaultResultSetHandler相关的知识,希望对你有一定的参考价值。

ResultSetHandler负责处理两件事: (1)处理Statement执行后产生的结果集,生成结果列表 (2)处理存储过程执行后的输出参数
ResultSetHandler是一个接口,提供了两个函数分别用来处理普通操作和存储过程的结果,
源码如下:
/**
 * @author Clinton Begin
 */
public interface ResultSetHandler 

  <E> List<E> handleResultSets(Statement stmt) throws SQLException;

  void handleOutputParameters(CallableStatement cs) throws SQLException;



ResultSetHandler的具体实现类是DefaultResultSetHandler,其实现的步骤就是将Statement执行后的结果集,按照Mapper文件中配置的ResultType或ResultMap来封装成对应的对象,最后将封装的对象返回即可,
DefaultResultSetHandler源码如下:

//ResultSetHandler具体实现类
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
  // 此Map用来保存当前层级内部的结果对象(一对多关系的多方对象),key为combinedKey
  private final Map<CacheKey, Object> nestedResultObjects = new HashMap<CacheKey, Object>();
  // 此Map用来保存当前层级的根对象(一对多关系中的一方对象),key为absoluteKey
  private final Map<CacheKey, Object> ancestorObjects = new HashMap<CacheKey, Object>();
  private final Map<String, String> ancestorColumnPrefix = new HashMap<String, String>();

  // multiple resultsets
  private final Map<String, ResultMapping> nextResultMaps = new HashMap<String, ResultMapping>();
  private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<CacheKey, List<PendingRelation>>();

  private static class PendingRelation 
    public MetaObject metaObject;
    public ResultMapping propertyMapping;
  

  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 
    try 
      final String resultMapId = parameterMapping.getResultMapId();
      final ResultMap resultMap = configuration.getResultMap(resultMapId);
      final DefaultResultHandler resultHandler = new DefaultResultHandler(objectFactory);
      final ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration);
      handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
      metaParam.setValue(parameterMapping.getProperty(), resultHandler.getResultList());
     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<Object>();

    int resultSetCount = 0;
	//获取第一个结果值
    ResultSetWrapper rsw = getFirstResultSet(stmt);
	//获得resultMap
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
	//这边应该为1吧,一般resultMap为一个
    int resultMapCount = resultMaps.size();
	//判断是否有resultMap,没有的话抛出异常
    validateResultMapsCount(rsw, resultMapCount);
    while (rsw != null && resultMapCount > resultSetCount) 
	  //获得resultMap,实体类和表中数据字段的对应关系
      ResultMap resultMap = resultMaps.get(resultSetCount);
	  //将值设置成对应的resultmap对象
      handleResultSet(rsw, resultMap, multipleResults, null);
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    

    String[] resultSets = mappedStatement.getResulSets();
    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);
  
  //获得第一个值,并将值打包
  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) throws SQLException 
    // 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();
          return rs != null ? new ResultSetWrapper(rs, configuration) : null;
        
      
     catch (Exception e) 
      // Intentionally ignored.
    
    return null;
  
	//关闭resultSet
  private void closeResultSet(ResultSet rs) 
    try 
      if (rs != null) 
        rs.close();
      
     catch (SQLException e) 
      // ignore
    
  

  private void cleanUpAfterHandlingResultSet() 
    nestedResultObjects.clear();
    ancestorColumnPrefix.clear();
  
  
  //校验结果的resultMap,如果没有的话就抛出异常
  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) 
		// 创建一个新对象
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
		  //将查询到的每个字段和Bean实体中的属性对应起来,生成一个Result对象
          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
		  //结果映射对象及值添加到multipleResults中
          multipleResults.add(defaultResultHandler.getResultList());
         else 
          handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
        
      
     finally 
      // issue #228 (close resultsets)
      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
  //
	//操作列值
  private 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);
    
  
 //判断记录行数
  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<Object>();
	//跳过RowBounds设置的offset值
    skipRows(rsw.getResultSet(), rowBounds);
	//判断数据是否小于limit,如果小于limit的话就不断的循环取值
    while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) 
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
      Object rowValue = getRowValue(rsw, discriminatedResultMap);
      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 
      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) throws SQLException 
	//判断数据是否小于limit,小于返回true
    return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
  
  //跳过不需要的行,应该就是rowbounds设置的limit和offset
  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 
	  //跳过RowBounds中设置的offset条数据
      for (int i = 0; i < rowBounds.getOffset(); i++) 
        rs.next();
      
    
  

  //
  // GET VALUE FROM ROW FOR SIMPLE RESULT MAP
  //

  private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException 
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
	//结果的映射对象
    Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null);
    if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) 
      final MetaObject metaObject = configuration.newMetaObject(resultObject);
      boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
      if (shouldApplyAutomaticMappings(resultMap, false)) 
        foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
      
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
      foundValues = lazyLoader.size() > 0 || foundValues;
      resultObject = foundValues ? resultObject : null;
      return resultObject;
    
    return resultObject;
  
	//用于判断是否是bean实体变量和表中字段自动映射
  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 
    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();
        // issue #377, call setter on nulls
        if (value != DEFERED
            && property != null
            && (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive()))) 
          metaObject.setValue(property, value);
        
        if (value != null || value == DEFERED) 
          foundValues = true;
        
      
    
    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 
      final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
      final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      return typeHandler.getResult(rs, column);
    
  
  //
  private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException 
    final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
    boolean foundValues = false;
	//获得列名
    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());
      if (property != null && metaObject.hasSetter(property)) 
        final Class<?> propertyType = metaObject.getSetterType(property);
        if (typeHandlerRegistry.hasTypeHandler(propertyType)) 
          final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
          final Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
          // issue #377, call setter on nulls
          if (value != null || configuration.isCallSettersOnNulls()) 
            if (value != null || !propertyType.isPrimitive()) 
              metaObject.setValue(property, value);
            
            foundValues = true;
          
        
      
    
    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.get(cacheKey);
    // issue #255
    if (relations == null) 
      relations = new ArrayList<DefaultResultSetHandler.PendingRelation>();
      pendingRelations.put(cacheKey, relations);
    
    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 
    final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();
    final List<Object> constructorArgs = new ArrayList<Object>();
	//结果对象
    final Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
    if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) 
		//获取配置的resultMap的字段与表中数据的映射关系
      final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
      for (ResultMapping propertyMapping : propertyMappings) 
        // issue gcode #109 && issue #149
        if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) 
          return configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
        
      
    
    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 (typeHandlerRegistry.hasTypeHandler(resultType)) 
		//基本类型
      return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
     else if (!constructorMappings.isEmpty()) 
		//有参数构造函数
      return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
     else if (resultType.isInterface() || metaType.hasDefaultConstructor()) 
		//普通的bean类型
      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 e) 
        throw new ExecutorException("Could not process result for mapping: " + constructorMapping, e);
       catch (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 
    for (Constructor<?> constructor : resultType.getDeclaredConstructors()) 
      if (typeNames(constructor.getParameterTypes()).equals(rsw.getClassNames())) 
        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;
      
    
    throw new ExecutorException("No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames());
  

  private List<String> typeNames(Class<?>[] parameterTypes) 
    List<String> names = new ArrayList<String>();
    for (Class<?> type : parameterTypes) 
      names.add(type.getName());
    
    return names;
  
	//创建原型结果
  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)) 
		//如果已经有一级缓存了,则延迟加载(实际上deferLoad方法中可以看到则是立即加载)
        executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType);
        value = DEFERED;
       else 
		//否则lazyLoader.addLoader 需要延迟加载则addLoader
    	//或者ResultLoader.loadResult 不需要延迟加载则立即加载
        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<Object, Object>();
     else 
      return objectFactory.create(parameterType);
    
  

  //
  // DISCRIMINATOR
 //
  public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException 
    Set<String> pastDiscriminators = new HashSet<String>();
    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<Object>();
    //跳过rowBounds指定offset行偏移量
	skipRows(rsw.getResultSet(), rowBounds);
    Object rowValue = null;
	//如何定义应该处理:上下文没有主动停止,结果集还有记录,且上下文中结果对象数量不足时,应该继续处理
    while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) 
     // 解决鉴别过的结果映射,逻辑如下:
     // 获取结果映射中的鉴别器,通过鉴别指定字段通过配置对象获取对应的另一个结果映射,循环往复,
     // 直到找不到鉴别器为止,返回最终的结果映射
	 final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
      // 创建缓存key,如何创建?
	  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, rowKey, null, partialObject);
       else 
        rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, 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());
    
  

  //
  // GET VALUE FROM ROW FOR NESTED RESULT MAP
  //
   //
  private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, CacheKey absoluteKey, String columnPrefix, Object partialObject) throws SQLException 
    final String resultMapId = resultMap.getId();
    Object resultObject = partialObject;
    if (resultObject != null) 
      final MetaObject metaObject = configuration.newMetaObject(resultObject);
      putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
      applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
      ancestorObjects.remove(absoluteKey);
     else 
      final ResultLoaderMap lazyLoader = new ResultLoaderMap();
      resultObject = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
      if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) 
        final MetaObject metaObject = configuration.newMetaObject(resultObject);
        boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
        if (shouldApplyAutomaticMappings(resultMap, true)) 
          foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
        
        foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
        putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
        foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
        ancestorObjects.remove(absoluteKey);
        foundValues = lazyLoader.size() > 0 || foundValues;
        resultObject = foundValues ? resultObject : null;
      
      if (combinedKey != CacheKey.NULL_CACHE_KEY) 
        nestedResultObjects.put(combinedKey, resultObject);
      
    
    return resultObject;
  

  private void putAncestor(CacheKey rowKey, Object resultObject, String resultMapId, String columnPrefix) 
    if (!ancestorColumnPrefix.containsKey(resultMapId)) 
      ancestorColumnPrefix.put(resultMapId, columnPrefix);
    
    ancestorObjects.put(rowKey, 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);
          CacheKey rowKey = null;
          Object ancestorObject = null;
          if (ancestorColumnPrefix.containsKey(nestedResultMapId)) 
            rowKey = createRowKey(nestedResultMap, rsw, ancestorColumnPrefix.get(nestedResultMapId));
            ancestorObject = ancestorObjects.get(rowKey);
          
          if (ancestorObject != null) 
            if (newObject) 
              linkObjects(metaObject, resultMapping, ancestorObject); // issue #385
            
           else 
            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.getResultSet())) 
              rowValue = getRowValue(rsw, nestedResultMap, combinedKey, rowKey, 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, ResultSet rs) throws SQLException 
    Set<String> notNullColumns = resultMapping.getNotNullColumns();
    boolean anyNotNullColumnHasValue = true;
    if (notNullColumns != null && !notNullColumns.isEmpty()) 
      anyNotNullColumnHasValue = false;
      for (String column: notNullColumns) 
        rs.getObject(prependPrefix(column, columnPrefix));
        if (!rs.wasNull()) 
          anyNotNullColumnHasValue = true;
          break;
        
      
    
    return anyNotNullColumnHasValue;
  

  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.size() == 0) 
      if (Map.class.isAssignableFrom(resultMap.getType())) 
        createRowKeyForMap(rsw, cacheKey);
       else 
        createRowKeyForUnmappedProperties(resultMap, rsw, cacheKey, columnPrefix);
      
     else 
      createRowKeyForMappedProperties(resultMap, rsw, cacheKey, resultMappings, columnPrefix);
    
    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.size() == 0) 
      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) 
            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;
  



以上是关于Mybatis源码分析之结果封装ResultSetHandler和DefaultResultSetHandler的主要内容,如果未能解决你的问题,请参考以下文章

mybatis的缓存机制源码分析之二级缓存解析

myBatis执行流程及源码分析

mybatis 那么垃圾 为什么有人用,除了封装一下结果集 我不知道他还干了什么。

MyBatis核心源码深度剖析SQL执行过程

mybatis源码配置文件解析之五:解析mappers标签(解析XML映射文件)

精尽MyBatis源码分析 - SQL执行过程之 StatementHandler