Mybatis-DefaultResultSetHandler(一)源碼解析

Mybatis3.5.1源碼分析

  1. Mybatis-SqlSessionFactoryBuilder邢隧,XMLConfigBuilder扑庞,XPathParser源碼解析
  2. Mybatis-Configuration源碼解析
  3. Mybatis-事務(wù)對象源碼解析
  4. Mybatis-數(shù)據(jù)源源碼解析
  5. Mybatis緩存策略源碼解析
  6. Mybatis-DatabaseIdProvider源碼解析
  7. Mybatis-TypeHandler源碼解析
  8. Mybatis-Reflector源碼解析
  9. Mybatis-ObjectFactory,ObjectWrapperFactory源碼分析
  10. Mybatis-Mapper各類標(biāo)簽封裝類源碼解析
  11. Mybatis-XMLMapperBuilder,XMLStatmentBuilder源碼分析
  12. Mybatis-MapperAnnotationBuilder源碼分析
  13. [Mybatis-MetaObject,MetaClass源碼解析]http://www.reibang.com/p/f51fa552f30a)
  14. Mybatis-LanguageDriver源碼解析
  15. Mybatis-SqlSource源碼解析
  16. Mybatis-SqlNode源碼解析
  17. Mybatis-KeyGenerator源碼解析
  18. Mybatis-Executor源碼解析
  19. Mybatis-ParameterHandler源碼解析
  20. Mybatis-StatementHandler源碼解析
  21. Mybatis-DefaultResultSetHandler(一)源碼解析
  22. Mybatis-DefaultResultSetHandler(二)源碼解析
  23. Mybatis-ResultHandler,Cursor,RowBounds 源碼分析
  24. Mybatis-MapperProxy源碼解析
  25. Mybatis-SqlSession源碼解析
  26. Mybatis-Interceptor源碼解析

DefaultResultSetHandler

package org.apache.ibatis.executor.resultset;

/**
 * 默認(rèn)的結(jié)果集處理器
 * <p>
 *     別名說明:
 *     <ol>
 *         <li>Mapper.xml的resultMap標(biāo)簽信息封裝類對象 簡稱 resultMap標(biāo)簽對象</li>
 *         <li>根據(jù)resultMap對象與結(jié)果集構(gòu)建出來的java類型對象,簡稱為 結(jié)果對象</li>
 *     </ol>
 *
 * </p>
 * <p>參考博客:<a >https://my.oschina.net/u/3768341/blog/3040013</a></p>
 * <p>https://my.oschina.net/heweipo/blog/621613</p>
 * @author Clinton Begin
 * @author Eduardo Macarron
 * @author Iwao AVE!
 * @author Kazuki Shimizu
 */
public class DefaultResultSetHandler implements ResultSetHandler {

  /**
   * 標(biāo)記著待定的對象
   */
  private static final Object DEFERRED = new Object();

  /**
   * 執(zhí)行器
   */
  private final Executor executor;
  /**
   * mybatis全局配置信息
   */
  private final Configuration configuration;
  /**
   *  Mapper.xml文件的select,delete,update,insert這些DML標(biāo)簽的封裝類
   */
  private final MappedStatement mappedStatement;
  /**
   * Mybatis的分頁對象
   */
  private final RowBounds rowBounds;
  /**
   * 參數(shù)處理器
   */
  private final ParameterHandler parameterHandler;
  /**
   * 結(jié)果處理器
   */
  private final ResultHandler<?> resultHandler;
  /**
   * 參數(shù)映射與可執(zhí)行SQL封裝類對象
   */
  private final BoundSql boundSql;
  /**
   * 類型處理器注冊器對象
   */
  private final TypeHandlerRegistry typeHandlerRegistry;
  /**
   * 對象工廠,從mybatis全局配置信息中獲取
   */
  private final ObjectFactory objectFactory;
  /**
   * 反射工廠,從mybatis全局配置信息中獲取
   */
  private final ReflectorFactory reflectorFactory;

  // nested resultmaps
  /**
   * key=緩存Key,value=嵌套的結(jié)果對象
   */
  private final Map<CacheKey, Object> nestedResultObjects = new HashMap<>();
  private final Map<String, Object> ancestorObjects = new HashMap<>();
  /**
   * 上一次嵌套的resultMap對象所構(gòu)建出來的對象
   */
  private Object previousRowValue;

  // multiple resultsets
  private final Map<String, ResultMapping> nextResultMaps = new HashMap<>();
  /**
   * PendingRelation是DefaultResultSetHandler的內(nèi)部靜態(tài)類骂铁,記錄了當(dāng)前結(jié)果對象對應(yīng)的MetaObject對象以及parentMapping對象
   * 該對象就為CacheKey對象跟全部的PendingRelation對象的映射
   */
  private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<>();

  // Cached Automappings
  /**
   * 自動映射關(guān)系緩存Map
   */
  private final Map<String, List<UnMappedColumnAutoMapping>> autoMappingsCache = new HashMap<>();

  // temporary marking flag that indicate using constructor mapping (use field to reduce memory usage)
  // 表明使用構(gòu)造函數(shù)映射關(guān)系的臨時標(biāo)志標(biāo)記(使用成員變量來減少內(nèi)存開銷)
  /**
   * 當(dāng)前結(jié)果對象是否使用了非無參構(gòu)造函數(shù)進(jìn)行構(gòu)建的標(biāo)記
   */
  private boolean useConstructorMappings;

  /**
   * 待定關(guān)系
   */
  private static class PendingRelation {
    /**
     * 元對象
     */
    public MetaObject metaObject;
    /**
     * 結(jié)果映射
     */
    public ResultMapping propertyMapping;
  }

  private static class UnMappedColumnAutoMapping {
    /**
     * 字段名
     */
    private final String column;
    /**
     * 屬性名
     */
    private final String property;
    /**
     * TypeHandler 處理器
     */
    private final TypeHandler<?> typeHandler;
    /**
     * 是否為基本屬性
     */
    private final boolean primitive;

    /**
     *
     * @param column 字段名
     * @param property 屬性名
     * @param typeHandler TypeHandler 處理器
     * @param primitive 是否為基本屬性
     */
    public UnMappedColumnAutoMapping(String column, String property, TypeHandler<?> typeHandler, boolean primitive) {
      this.column = column;
      this.property = property;
      this.typeHandler = typeHandler;
      this.primitive = primitive;
    }
  }

  /**
   *
   * @param executor 執(zhí)行器
   * @param mappedStatement Mapper.xml文件的select,delete,update,insert這些DML標(biāo)簽的封裝類
   * @param parameterHandler 參數(shù)處理器
   * @param resultHandler 結(jié)果處理器
   * @param boundSql 參數(shù)映射與可執(zhí)行SQL封裝類對象
   * @param rowBounds Mybatis的分頁對象
   */
  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 {
    //獲取參數(shù)對象
    final Object parameterObject = parameterHandler.getParameterObject();
    //構(gòu)建參數(shù)元對象
    final MetaObject metaParam = configuration.newMetaObject(parameterObject);
    //獲取參數(shù)映射集合
    final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    //遍歷參數(shù)映射集合
    for (int i = 0; i < parameterMappings.size(); i++) {
      //獲取參數(shù)映射
      final ParameterMapping parameterMapping = parameterMappings.get(i);
      //如果參數(shù)映射的模式為輸出參數(shù) 或者 參數(shù)映射的模式為輸入/輸出參數(shù)
      if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
        //如果參數(shù)映射配置java類型是ResultSet
        if (ResultSet.class.equals(parameterMapping.getJavaType())) {
        //處理結(jié)果游標(biāo)的輸出參數(shù),將結(jié)果對象集合賦值到參數(shù)對象對應(yīng)的屬性中
          handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam);
        } else {
          //獲取類型處理器
          final TypeHandler<?> typeHandler = parameterMapping.getTypeHandler();
          //通過typeHandler獲取指定列位置的結(jié)果對象罩抗,然后賦值到參數(shù)對象對應(yīng)的屬性中
          metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1));
        }
      }
    }
  }

  /**
   * 處理結(jié)果游標(biāo)的輸出參數(shù)拉庵,將結(jié)果對象集合賦值到參數(shù)對象對應(yīng)的屬性中
   * @param rs 結(jié)果集
   * @param parameterMapping 對應(yīng)于paramterMap的paramter標(biāo)簽參數(shù)映射封裝類對象
   * @param metaParam 參數(shù)元對象
   */
  private void handleRefCursorOutputParameter(ResultSet rs, ParameterMapping parameterMapping, MetaObject metaParam) throws SQLException {
    //如果結(jié)果集為null
    if (rs == null) {
      return;
    }
    try {
      //獲取參數(shù)映射配置的resultMap標(biāo)簽Id
      final String resultMapId = parameterMapping.getResultMapId();
      //獲取resultMapId對應(yīng)的ResultMap對象
      final ResultMap resultMap = configuration.getResultMap(resultMapId);
      //將rs進(jìn)行包裝
      final ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration);
      //如果結(jié)果處理器為null
      if (this.resultHandler == null) {
        //默認(rèn)ResultHandler,通過ObjectFactory去構(gòu)建list來接收結(jié)果
        //構(gòu)建一個默認(rèn)結(jié)果處理器套蒂,里面就是通過objectFactory構(gòu)建list對象,本質(zhì)是一個list.
        final DefaultResultHandler resultHandler = new DefaultResultHandler(objectFactory);
        //處理結(jié)果集
        handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
        //將結(jié)果對象集合賦值到參數(shù)對象對應(yīng)的屬性中
        metaParam.setValue(parameterMapping.getProperty(), resultHandler.getResultList());
      } else {
        //處理結(jié)果集
        handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
      }
    } finally {
      // issue #228 (close resultsets) 關(guān)閉結(jié)果集,捕捉SQLException并不作任何處理
      closeResultSet(rs);
    }
  }

  //
  // HANDLE RESULT SETS
  //

  /**
   * 處理 {@code stmt} 中的所有結(jié)果集钞支,返回結(jié)果對象集合
   * @param stmt SQL容器
   */
  @Override
  public List<Object> handleResultSets(Statement stmt) throws SQLException {
    //設(shè)置日志的上下文
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
    //初始化一個集合對象,用于保存多個結(jié)果對象
    final List<Object> multipleResults = new ArrayList<>();
    //初始化結(jié)果集數(shù)量為0
    int resultSetCount = 0;
    //獲取第一個結(jié)果集對象
    ResultSetWrapper rsw = getFirstResultSet(stmt);
    //獲取ResultMap標(biāo)簽對象集合
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    //獲取集合元素數(shù)量
    int resultMapCount = resultMaps.size();
    //驗證ResultMap標(biāo)簽對象數(shù)量,如果rsw不為null且ResultMapCount小于1操刀,就會拋出異常
    validateResultMapsCount(rsw, resultMapCount);
    //如果結(jié)果集包裝類對象不為null 且 配置的ResultMap標(biāo)簽對象數(shù)量大于結(jié)果集數(shù)量
    while (rsw != null && resultMapCount > resultSetCount) {
      //從集合中獲取ResultMap標(biāo)簽對象
      ResultMap resultMap = resultMaps.get(resultSetCount);
      /**
       * 構(gòu)建出來的結(jié)果對象,如果父級結(jié)果屬性映射不為null烁挟,會將結(jié)果對象賦值到父級結(jié)果屬性對應(yīng)的結(jié)果對象中,
       * 否則將結(jié)果對象加入到reusltHandler中馍刮。最后從reusltHandler中取的最終的結(jié)果對象加入到多個結(jié)果
       * 對象集合中
       */
      handleResultSet(rsw, resultMap, multipleResults, null);
      //獲取下一個結(jié)果集對象
      rsw = getNextResultSet(stmt);
      //清空所有的嵌套結(jié)果對象
      cleanUpAfterHandlingResultSet();
      //每處理完一次信夫,結(jié)果集數(shù)量+1
      resultSetCount++;
    }

    //獲取配置的結(jié)果集名
    String[] resultSets = mappedStatement.getResultSets();
    //如果結(jié)果集不為null
    if (resultSets != null) {
      //如果結(jié)果包裝對象不為null 而且 結(jié)果集數(shù)量小于配置的結(jié)果集名數(shù)量
      while (rsw != null && resultSetCount < resultSets.length) {
        //獲取父級結(jié)果屬性映射對象
        ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
        //如果父級結(jié)果屬性映射對象不為null
        if (parentMapping != null) {
          //獲取嵌套的resultMap標(biāo)簽對象Id
          String nestedResultMapId = parentMapping.getNestedResultMapId();
          //獲取nestedResultMapId對應(yīng)的ResultMap標(biāo)簽對象
          ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
          /**
           * 構(gòu)建出來的結(jié)果對象,如果父級結(jié)果屬性映射不為null窃蹋,會將結(jié)果對象賦值到父級結(jié)果屬性對應(yīng)的結(jié)果對象中卡啰,
           *  否則將結(jié)果對象加入到reusltHandler中。最后從reusltHandler中取的最終的結(jié)果對象加入到多個結(jié)果
           *  對象集合中
           */
          handleResultSet(rsw, resultMap, null, parentMapping);
        }
        //獲取下一個結(jié)果集警没,并封裝到包裝類中
        rsw = getNextResultSet(stmt);
        //清空所有的嵌套結(jié)果對象
        cleanUpAfterHandlingResultSet();
        //每處理完一次匈辱,結(jié)果集數(shù)量+1
        resultSetCount++;
      }
    }

    //如果multipleResults只有一個元素,只會返回該元素對象杀迹;否則返回multipleResult
    return collapseSingleResultList(multipleResults);
  }

  @Override
  public <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling cursor results").object(mappedStatement.getId());
    //獲取第一個結(jié)果集對象亡脸,并包裝起來
    ResultSetWrapper rsw = getFirstResultSet(stmt);
    //獲取ResultMap標(biāo)簽對象集合
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    //獲取集合的元素數(shù)量
    int resultMapCount = resultMaps.size();
    //驗證ResultMap標(biāo)簽對象數(shù)量,如果rsw不為null且ResultMapCount小于1,就會拋出異常
    validateResultMapsCount(rsw, resultMapCount);
    //檢查集合是否為1
    if (resultMapCount != 1) {
      //游標(biāo)結(jié)果不能映射到多個ResultMap標(biāo)簽對象
      throw new ExecutorException("Cursor results cannot be mapped to multiple resultMaps");
    }
    //獲取唯一的一個ResultMap標(biāo)簽對象
    ResultMap resultMap = resultMaps.get(0);
    //返回默認(rèn)的mybatis游標(biāo)實例
    return new DefaultCursor<>(this, resultMap, rsw, rowBounds);
  }

  /**
   * 獲取第一個結(jié)果集
   * @param stmt SQL腳本容器
   * @return 結(jié)果集包裝類對象
   */
  private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
    //獲取結(jié)果集
    ResultSet rs = stmt.getResultSet();
    //如果結(jié)果集為null
    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)
      //前進(jìn)得到第一個結(jié)果集以防驅(qū)動不返回結(jié)果集的第一個結(jié)果
      /**
       * getMoreResults:移動到Statement對象的下一個結(jié)果,如果下一個結(jié)果是ResultSet對象树酪,返回true,
       * 如果是一個更新記錄數(shù)或者已經(jīng)沒有更多的結(jié)果時浅碾,返回false
       */
      if (stmt.getMoreResults()) {
        //獲取結(jié)果集
        rs = stmt.getResultSet();
      } else {
        //如果沒有結(jié)果集
        //getUpdateCount:更新記錄數(shù),沒有時為-1
        if (stmt.getUpdateCount() == -1) {
          /**
           * 當(dāng)((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))
           * 就表示已經(jīng)沒有更多結(jié)果
           */
          // no more results. Must be no resultset
          break;
        }
      }
    }
    //如果結(jié)果集不為null续语,就包裝起來返回出去垂谢;否則,返回null
    return rs != null ? new ResultSetWrapper(rs, configuration) : null;
  }

  /**
   * 獲取下一個結(jié)果集
   * @param stmt SQL腳本容器
   * @return 結(jié)果集包裝類對象
   */
  private ResultSetWrapper getNextResultSet(Statement stmt) {
    // Making this method tolerant of bad JDBC drivers
    //使用這個方法能增強(qiáng)對JDBC驅(qū)動的容錯率
    try {
      //檢索這個數(shù)據(jù)庫是否支持從一個單一調(diào)用方法執(zhí)行獲得多個結(jié)果集對象
      if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {
        // Crazy Standard JDBC way of determining if there are more results
        //瘋狂的標(biāo)準(zhǔn)JDBC確定是否有更多結(jié)果的方法
        //!stmt.getMoreResults() && stmt.getUpdateCount() == -1:表示已經(jīng)沒有更多結(jié)果
        //如果有更多結(jié)果
        if (!(!stmt.getMoreResults() && stmt.getUpdateCount() == -1)) {
          //獲取結(jié)果集
          ResultSet rs = stmt.getResultSet();
          //如果結(jié)果集對象不為null
          if (rs == null) {
            //遞歸嘗試重新獲取下個一個結(jié)果集
            return getNextResultSet(stmt);
          } else {
            //將結(jié)果集對象包裝起來返回
            return new ResultSetWrapper(rs, configuration);
          }
        }
      }
    } catch (Exception e) {
      // Intentionally ignored.
    }
    return null;
  }

  /**
   * 關(guān)閉結(jié)果集,捕捉SQLException并不作任何處理
   * @param rs 結(jié)果集
   */
  private void closeResultSet(ResultSet rs) {
    try {
      //如果結(jié)果集不為null
      if (rs != null) {
        //關(guān)閉
        rs.close();
      }
    } catch (SQLException e) {
      // ignore 捕捉SQLException并不作任何處理
    }
  }

  /**
   * 清空所有的嵌套結(jié)果對象
   */
  private void cleanUpAfterHandlingResultSet() {
    nestedResultObjects.clear();
  }

  /**
   * 驗證ResultMap標(biāo)簽對象數(shù)量,如果rsw不為null且ResultMapCount小于1疮茄,就會拋出異常
   * @param rsw 結(jié)果集包裝類對象
   * @param resultMapCount ResultMap標(biāo)簽對象數(shù)量
   */
  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.");
    }
  }

  /**
   * 構(gòu)建出來的結(jié)果對象,如果父級結(jié)果屬性映射不為null滥朱,會將結(jié)果對象賦值到父級結(jié)果屬性對應(yīng)的結(jié)果對象中,
   *  否則將結(jié)果對象加入到reusltHandler中力试。最后從reusltHandler中取的最終的結(jié)果對象加入到多個結(jié)果
   *  對象集合中
   * @param rsw 結(jié)果集包裝對象
   * @param resultMap resultMap標(biāo)簽對象
   * @param multipleResults 多個結(jié)果對象集合
   * @param parentMapping 父級結(jié)果屬性映射
   * @throws SQLException
   */
  private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
      //如果 父級結(jié)果屬性映射不為null
      if (parentMapping != null) {
        /**
         * 構(gòu)建出來的結(jié)果對象,如果父級結(jié)果屬性映射不為null徙邻,會將結(jié)果對象賦值到父級結(jié)果屬性對應(yīng)的結(jié)果對象中,
         * 否則將結(jié)果對象加入到reusltHandler中
         */
        //這里因為paranetMapping已經(jīng)確定不為null了畸裳,所以resultHandler傳入null也不會有問題缰犁。
        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
      } else {
        //如果結(jié)果處理器對象為null
        if (resultHandler == null) {
          //創(chuàng)建一個默認(rèn)結(jié)果處理類對象
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
          /**
           * 構(gòu)建出來的結(jié)果對象,如果父級結(jié)果屬性映射不為null,會將結(jié)果對象賦值到父級結(jié)果屬性對應(yīng)的結(jié)果對象中,
           *  否則將結(jié)果對象加入到reusltHandler中
           */
          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
          //將結(jié)果對象加入到多個結(jié)果對象集合中
          multipleResults.add(defaultResultHandler.getResultList());
        } else {
          /**
           * 構(gòu)建出來的結(jié)果對象,如果父級結(jié)果屬性映射不為null帅容,會將結(jié)果對象賦值到父級結(jié)果屬性對應(yīng)的結(jié)果對象中薇芝,
           *  否則將結(jié)果對象加入到reusltHandler中
           */
          handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
        }
      }
    } finally {
      // issue #228 (close resultsets)
      //關(guān)閉結(jié)果集,捕捉SQLException并不作任何處理
      closeResultSet(rsw.getResultSet());
    }
  }

  /**
   * 折疊只有一個結(jié)果列表
   * @param multipleResults 存放著多個結(jié)果的集合
   * @return 如果multipleResults只有一個元素,只會返回該元素對象丰嘉;否則返回multipleResult
   */
  @SuppressWarnings("unchecked")
  private List<Object> collapseSingleResultList(List<Object> multipleResults) {
    return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults;
  }

  //
  // HANDLE ROWS FOR SIMPLE RESULTMAP
  //

  /**
   * 構(gòu)建出來的結(jié)果對象,如果父級結(jié)果屬性映射不為null夯到,會將結(jié)果對象賦值到父級結(jié)果屬性對應(yīng)的結(jié)果對象中,
   * 否則將結(jié)果對象加入到reusltHandler中
   * @param rsw 結(jié)果集包裝類對象
   * @param resultMap resultMap標(biāo)簽信息封裝類對象
   * @param resultHandler 一般為 {@link DefaultResultHandler} 實例
   * @param rowBounds mybatis的分頁
   * @param parentMapping 父級結(jié)果屬性映射
   */
  public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    //如果存在嵌套的resultMap
    if (resultMap.hasNestedResultMaps()) {
      //確保沒有超過分頁行范圍
      ensureNoRowBounds();
      //檢查是否可以使用resultHandler
      checkResultHandler();
      //為嵌套的ResultMap標(biāo)簽對象饮亏,將構(gòu)建出來的結(jié)果對象加入到reusltHandler中
      handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    } else {
      // 根據(jù)結(jié)果集包裝類對象和簡單的ResultMap標(biāo)簽對象耍贾,構(gòu)建成結(jié)果對象并加入到resultHandler中
      handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    }
  }

  /**
   * 確保沒有超過分頁行范圍
   * <p>
   *     只有當(dāng)isSafeRowsEnable(允許在嵌套語句中使用行分界(RowBounds),默認(rèn)為false路幸,不允許)為ture的時候荐开,才會檢查 {@link #rowBounds}的行范圍是否超過最大值和最小值,超過時會拋出異常简肴。
   * </p>
   */
  private void ensureNoRowBounds() {
    //isSafeRowsEnable:允許在嵌套語句中使用行分界(RowBounds)晃听,默認(rèn)為false,不允許
    //當(dāng)允許時砰识,會判斷rowBound的范圍是否超過最大值和最小值能扒,超過時會拋出異常。
    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.");
    }
  }

  /**
   * 檢查是否可以使用resultHandler
   */
  protected void checkResultHandler() {
    //SafeResultHandlerEnabled:允許在嵌套語句中使用分頁(ResultHandler)辫狼。如果允許使用則設(shè)置為 false初斑。
    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.");
    }
  }

  /**
   * 根據(jù)結(jié)果集包裝類對象和簡單的ResultMap標(biāo)簽對象,構(gòu)建成結(jié)果對象
   * @param rsw 結(jié)果集包裝類對象
   * @param resultMap ResultMap標(biāo)簽對象
   * @param resultHandler 結(jié)果處理器
   * @param rowBounds Mybatis的分頁對象
   * @param parentMapping 父級屬性結(jié)果映射
   * @throws SQLException
   */
  private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
      throws SQLException {
    //新建一個默認(rèn)的結(jié)果上下文
    DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
    //獲取結(jié)果集
    ResultSet resultSet = rsw.getResultSet();
    ////跳過rowBounds.offset記錄數(shù)
    skipRows(resultSet, rowBounds);
    //如果還有結(jié)果需要處理 而且 結(jié)果集還沒有關(guān)閉 而且 結(jié)果集還有數(shù)據(jù)
    while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
      //逐層解析resultMap鑒別器膨处,取得最終的ResultMap標(biāo)簽對象
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
      //根據(jù)rsw 和resultMap 構(gòu)建出 {@link ResultMap#getType()} 類型的對象
      Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
      /**
       * 保存對象,如果parentMaping 不為null,就將結(jié)果對象添加到parentMapping
       * 的metaObject中;否則见秤,調(diào)用結(jié)果處理器,將結(jié)果對象添加到結(jié)果處理器中
       */
      storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    }
  }

  /**
   * 保存對象,如果 {@code parentMaping} 不為null,就將結(jié)果對象添加到 {@code parentMapping}
   * 的metaObject中;否則真椿,調(diào)用結(jié)果處理器鹃答,將結(jié)果對象添加到結(jié)果處理器中
   * @param resultHandler 結(jié)果處理類對象
   * @param resultContext 結(jié)果上下文
   * @param rowValue resultMap對象
   * @param parentMapping 結(jié)果映射
   * @param rs 結(jié)果集
   */
  private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
    //如果上一層的ResultMapping對象不為null
    if (parentMapping != null) {
      //將嵌套對象記錄到外層元對象相應(yīng)的屬性中
      linkToParents(rs, parentMapping, rowValue);
    } else {
      //調(diào)用結(jié)果處理器,將結(jié)果對象添加到結(jié)果處理器中
      callResultHandler(resultHandler, resultContext, rowValue);
    }
  }

  /**
   * 調(diào)用結(jié)果處理器突硝,將結(jié)果對象添加到結(jié)果處理器中
   * @param resultHandler 結(jié)果處理器测摔,
   * @param resultContext 結(jié)果上下文
   * @param rowValue 結(jié)果對象
   */
  @SuppressWarnings("unchecked" /* because ResultHandler<?> is always ResultHandler<Object>*/)
  private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {
    //設(shè)置下一個結(jié)果對象
    resultContext.nextResultObject(rowValue);
    /**
     * 如果是DefaultResultHandler,就會將結(jié)果對象添加到內(nèi)部的List對象中
     * 如果是DefaultMapResultHandler狞换,會將結(jié)果對象添加到內(nèi)部的Map對象中
     */
    ((ResultHandler<Object>) resultHandler).handleResult(resultContext);
  }

  /**
   * 是否還有結(jié)果需要處理
   * @param context 結(jié)果上下文
   * @param rowBounds mybatis的分頁對象
   * @return 當(dāng) {@code context} 沒有停止避咆,且 {@code context} 的resultCount小于 {@code rowBounds} 的 limit是,為true修噪,否則為false
   */
  private boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) {
    return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
  }

  /**
   * 跳過rowBounds.offset記錄數(shù)
   * @param rs  結(jié)果集
   * @param rowBounds Mybatis的分頁對象
   * @throws SQLException
   */
  private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {
    //ResultSet.TYPE_FORWORD_ONLY 結(jié)果集的游標(biāo)只能向下滾動
    if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
      if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
        //absolute:將指針移動到此 ResultSet 對象的給定行編號查库。
        rs.absolute(rowBounds.getOffset());
      }
    } else {
      //通過ResultSet的next()改變rs的游標(biāo)位置直到達(dá)到rowBounds設(shè)置的offset
      for (int i = 0; i < rowBounds.getOffset(); i++) {
        if (!rs.next()) {
          break;
        }
      }
    }
  }

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


  /**
   * 根據(jù) {@code rsw} 和 {@code resultMap} 構(gòu)建出 {@link ResultMap#getType()} 類型的對象
   * @param rsw 結(jié)果集包裝類對象
   * @param resultMap Mapper.xml的resultMap標(biāo)簽信息封裝類對象
   * @param columnPrefix 列名前綴
   * @return {@link ResultMap#getType()} 類型的對象
   */
  private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
    //用來表示需要懶加載的屬性集,本質(zhì)是一個HashMap
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    //根據(jù) {@code rsw} 和 {@code resultMap} 的配置構(gòu)建結(jié)果對象
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
    //結(jié)果對象不為null但沒有對應(yīng)結(jié)果類型的TypeHandler
    if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      //構(gòu)建結(jié)果元對象
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      //當(dāng)前結(jié)果對象是否使用了非無參構(gòu)造函數(shù)進(jìn)行構(gòu)建的標(biāo)記
      boolean foundValues = this.useConstructorMappings;
      //是否可以應(yīng)用自動映射
      if (shouldApplyAutomaticMappings(resultMap, false)) {
        //對未能被映射列名映射關(guān)系集合進(jìn)行嘗試賦值黄琼,將結(jié)果集對應(yīng)數(shù)據(jù)賦值到結(jié)果對象對應(yīng)的屬性中
        foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
      }
      // applyPropertyMappings:根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象樊销,并賦值到結(jié)果對象中
      // 這時候的foundValue表示只有一個根據(jù)屬性映射和結(jié)果集成功構(gòu)建出對應(yīng)的目標(biāo)對象整慎,foundValue就為true
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
      foundValues = lazyLoader.size() > 0 || foundValues;
      /**
       * isReturnInstanceForEmptyRow:
       * 當(dāng)返回行的所有列都是空時,MyBatis默認(rèn)返回 null围苫。
       * 當(dāng)開啟這個設(shè)置時,MyBatis會返回一個空實例.請注意裤园,它也適用于嵌套的結(jié)果集(如集合或關(guān)聯(lián)).
       * (新增于 3.4.2)
       */
      rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    return rowValue;
  }

  /**
   * 是否可以應(yīng)用自動映射
   * @param resultMap Mapper.xml的resultMap標(biāo)簽信息封裝類對象
   * @param isNested 是否是嵌套的
   * @return 可以應(yīng)用自動映射,返回true剂府;否則返回false
   */
  private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {
    //如果配置了自動映射標(biāo)記
    if (resultMap.getAutoMapping() != null) {
      //自動映射
      return resultMap.getAutoMapping();
    } else {
      //如果是嵌套
      if (isNested) {
        //AutoMappingBehavior.FULL表示: 自動映射任意復(fù)雜的結(jié)果集(無論是否嵌套)拧揽。
        return AutoMappingBehavior.FULL == configuration.getAutoMappingBehavior();
      } else {
        //AutoMappingBehavior.NODE:取消自動映射
        //AutoMappingBehavior.PARTIAL:自動映射沒有定義嵌套結(jié)果集映射的結(jié)果集
        return AutoMappingBehavior.NONE != configuration.getAutoMappingBehavior();
      }
    }
  }

  //
  // PROPERTY MAPPINGS
  //

  /**
   * 根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象,并賦值到結(jié)果對象中
   * @param rsw 結(jié)果集包裝類對象
   * @param resultMap Mapper.xml的resultMap標(biāo)簽信息封裝類對象
   * @param metaObject 結(jié)果元對象
   * @param lazyLoader 用來表示需要懶加載的屬性集腺占,本質(zhì)是一個HashMap
   * @param columnPrefix 列名前綴
   * @return 成功根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象的標(biāo)記淤袜,哪怕只有一個成功,都會為true
   */
  private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
      throws SQLException {
    //獲取映射列名集合
    final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
    //成功根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象的標(biāo)記衰伯,哪怕只有一個成功铡羡,都會為true
    boolean foundValues = false;
    //獲取屬性映射關(guān)系集合,該集合不包括標(biāo)記為構(gòu)造函數(shù)的屬性映射關(guān)系
    final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
    //遍歷屬性映射關(guān)系
    for (ResultMapping propertyMapping : propertyMappings) {
      //拼接前綴與列名
      String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      //如果配置了嵌套的resultMapId
      if (propertyMapping.getNestedResultMapId() != null) {
        // the user added a column attribute to a nested result map, ignore it
        //用戶添加一個列屬性是一個嵌套映射結(jié)果,忽略它;
        column = null;
      }
      /**
       *  如果屬性映射存在組合ResultMaping列表
       *  或者 column不為null且映射列名集合中包含column
       *  或者 屬性映射配置了用于加載復(fù)雜類型的結(jié)果集
       */
      if (propertyMapping.isCompositeResult()
          || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
          || propertyMapping.getResultSet() != null) {
        //根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象
        Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
        // issue #541 make property optional
        //獲取屬性映射的屬性名
        final String property = propertyMapping.getProperty();
        //如果沒有配置屬性名
        if (property == null) {
          //跳過該屬性映射
          continue;
        //如果目標(biāo)對象是一個標(biāo)記為待定的對象
        } else if (value == DEFERRED) {
          //成功根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象的標(biāo)記設(shè)置為true
          foundValues = true;
          continue;
        }
        //如果目標(biāo)對象不為null
        if (value != null) {
          //成功根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象的標(biāo)記設(shè)置為true
          foundValues = true;
        }
        /**
         * isCallSetterOnNulls:
         * 指定當(dāng)結(jié)果集中值為 null 的時候是否調(diào)用映射對象的 setter(map 對象時為 put)方法意鲸,
         * 這在依賴于 Map.keySet() 或 null 值初始化的時候比較有用烦周。
         * 注意基本類型(int、boolean 等)是不能設(shè)置成 null 的怎顾。
         */
        //如果對象不為null,或者指定當(dāng)結(jié)果集中值為null的時候允許調(diào)用映射對象的setter(map對象時為 put)方法,且不是基本類型
        if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {
          // gcode issue #377, call setter on nulls (value is not 'found')
          //將value賦值到結(jié)果對象中的mapping.property屬性中
          metaObject.setValue(property, value);
        }
      }
    }
    return foundValues;
  }

  /**
   * 根據(jù)結(jié)果集和屬性映射對應(yīng)的目標(biāo)對象
   * @param rs 結(jié)果集
   * @param metaResultObject 結(jié)果元對象
   * @param propertyMapping 屬性映射
   * @param lazyLoader 用來表示需要懶加載的屬性集读慎,本質(zhì)是一個HashMap
   * @param columnPrefix 列名前綴
   * @return 根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象
   */
  private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
      throws SQLException {
    //如果屬性映射配置了嵌套select標(biāo)簽Id
    if (propertyMapping.getNestedQueryId() != null) {
      //構(gòu)建帶有嵌套查詢屬性的值對象
      return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
      //如果加載復(fù)雜類型的結(jié)果集
    } else if (propertyMapping.getResultSet() != null) {
      // 添加 {propertyMapping待定關(guān)系到待定關(guān)系映射集合 {@link #pendingRelations}
      addPendingChildRelation(rs, metaResultObject, propertyMapping);   // TODO is that OK?
      //返回標(biāo)記著待定的對象
      return DEFERRED;
    } else {
      //屬性映射的默認(rèn)情況處理
      //獲取屬性映射的TypeHandler
      final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
      //獲取屬性映射的列名,并拼接列名前綴
      final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      //從 ResultSet 中取出columnName對應(yīng)數(shù)據(jù)杆勇,然后轉(zhuǎn)換為 java 對象
      return typeHandler.getResult(rs, column);
    }
  }

  /**
   * 獲取未能被映射列名映射關(guān)系集合
   * @param rsw 結(jié)果集包裝類對象
   * @param resultMap Mapper.xml的resultMap標(biāo)簽信息封裝類對象
   * @param metaObject 結(jié)果元對象
   * @param columnPrefix 列名
   * @return 未能被映射列名映射關(guān)系集合
   * @throws SQLException
   */
  private List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
    //構(gòu)建autoMappingCache的Key
    final String mapKey = resultMap.getId() + ":" + columnPrefix;
    //獲取mapKey的自動映射集合
    List<UnMappedColumnAutoMapping> autoMapping = autoMappingsCache.get(mapKey);
    //如果自動映射集合為null
    if (autoMapping == null) {
      //初始化自動映射集合
      autoMapping = new ArrayList<>();
      //獲取未被映射的列名集合
      final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
      //遍歷未被映射的列名集合
      for (String columnName : unmappedColumnNames) {
        //將列名當(dāng)作屬性名
        String propertyName = columnName;
        //如果列名前綴不為null且不是空字符串
        if (columnPrefix != null && !columnPrefix.isEmpty()) {
          // When columnPrefix is specified,
          // ignore columns without the prefix.
          //當(dāng)列名前綴被指定了贪壳,就忽略沒有指定前綴的列
          //列名是以columnPrefix開頭
          if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
            //去掉columnPrefix賦值給propertyName
            propertyName = columnName.substring(columnPrefix.length());
          } else {
            //忽略沒有指定前綴的列
            continue;
          }
        }
        /**
         * isMapUnderscoreToCamelCase:是否開啟自動駝峰命名規(guī)則(camel case)映射饱亿,
         * 即從經(jīng)典數(shù)據(jù)庫列名 A_COLUMN 到經(jīng)典 Java 屬性名 aColumn 的類似映射
         */
        //查看結(jié)果對象是否存在propertyName屬性,存在便會返回該屬性名
        final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
        //如果屬性不為null且結(jié)果對象有這個屬性的setter方法
        if (property != null && metaObject.hasSetter(property)) {
          //如果配置的映射屬性名中有這個屬性
          if (resultMap.getMappedProperties().contains(property)) {
            //跳過
            continue;
          }
          //獲取結(jié)果對象的property的setter方法的參數(shù)類型
          final Class<?> propertyType = metaObject.getSetterType(property);
          //如果存在propertyType和columnName的jdbcType的TypeHandler
          if (typeHandlerRegistry.hasTypeHandler(propertyType, rsw.getJdbcType(columnName))) {
            //獲取propertyType和columnName的TypeHandler
            final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
            //構(gòu)建UnMappedColumnAutoMapping對象蚜退,并添加到autoMapping中
            autoMapping.add(new UnMappedColumnAutoMapping(columnName, property, typeHandler, propertyType.isPrimitive()));
          } else {
            //不存在propertyType和columnName的jdbcType的TypeHandler時
            /**
             * AutoMappingUnknownColumnBehavior: 指定發(fā)現(xiàn)自動映射目標(biāo)未知列(或者未知屬性類型)的行為
             * NONE:不做任何反應(yīng),默認(rèn)
             * WARNING:輸出提醒日志
             * FAILING:映射失敗 (拋出 SqlSessionException)
             */
            //AutoMappingUnknownColumnBehavior為枚舉類,doAction為枚舉方法彪笼。
            /**
             * 根據(jù)配置的AutoMappingUnknownColumnBehavior枚舉類钻注,作出相應(yīng)的處理,要么什么都不做配猫,要
             * 么輸出提醒日志幅恋,要么拋出SqlSessionException
             */
            configuration.getAutoMappingUnknownColumnBehavior()
                .doAction(mappedStatement, columnName, property, propertyType);
          }
        } else {
          //屬性為null或者結(jié)果對象沒有這個屬性的setter方法
          /**
           * 根據(jù)配置的AutoMappingUnknownColumnBehavior枚舉類,作出相應(yīng)的處理泵肄,要么什么都不做捆交,要
           * 么輸出提醒日志,要么拋出SqlSessionException
           */
          configuration.getAutoMappingUnknownColumnBehavior()
              .doAction(mappedStatement, columnName, (property != null) ? property : propertyName, null);
        }
      }
      //保存結(jié)果對象的自動自動映射集合
      autoMappingsCache.put(mapKey, autoMapping);
    }
    return autoMapping;
  }

  /**
   * 對未能被映射列名映射關(guān)系集合進(jìn)行嘗試賦值腐巢,將結(jié)果集對應(yīng)數(shù)據(jù)賦值到結(jié)果對象對應(yīng)的屬性中
   * @param rsw 結(jié)果集包裝類對象
   * @param resultMap Mapper.xml的resultMap標(biāo)簽信息封裝類對象
   * @param metaObject 結(jié)果元對象
   * @param columnPrefix 列名前綴
   * @return 成功根據(jù)自動映射關(guān)系集合的元素構(gòu)建出指定java類對象標(biāo)記品追,返回true;否則返回false
   */
  private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
    //獲取未能被映射列名映射關(guān)系集合
    List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
    //成功根據(jù)自動映射關(guān)系集合的元素構(gòu)建出指定java類對象標(biāo)記
    boolean foundValues = false;
    //如果自動映射關(guān)系集合不為空
    if (!autoMapping.isEmpty()) {
      //遍歷自動映射關(guān)系集合
      for (UnMappedColumnAutoMapping mapping : autoMapping) {
        //從 ResultSet 中取出columnName對應(yīng)數(shù)據(jù)冯丙,然后轉(zhuǎn)換為 java 對象
        final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
        //如果對象不為null
        if (value != null) {
          //只要有一個成功根據(jù)自動映射關(guān)系集合的元素構(gòu)建出指定java類對象肉瓦,標(biāo)記就會變成true
          foundValues = true;
        }
        /**
         * isCallSetterOnNulls:
         * 指定當(dāng)結(jié)果集中值為 null 的時候是否調(diào)用映射對象的 setter(map 對象時為 put)方法,
         * 這在依賴于 Map.keySet() 或 null 值初始化的時候比較有用。
         * 注意基本類型(int泞莉、boolean 等)是不能設(shè)置成 null 的哪雕。
         */
        //如果對象不為null,或者指定當(dāng)結(jié)果集中值為null的時候允許調(diào)用映射對象的setter(map對象時為 put)方法,且不是基本類型
        if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
          // gcode issue #377, call setter on nulls (value is not 'found')
          //將value賦值到結(jié)果對象中的mapping.property屬性中
          metaObject.setValue(mapping.property, value);
        }
      }
    }
    return foundValues;
  }

  // MULTIPLE RESULT SETS

  /**
   * 將嵌套對象記錄到外層元對象相應(yīng)的屬性中
   * @param rs 結(jié)果集
   * @param parentMapping 結(jié)果映射
   * @param rowValue 上一次嵌套的resultMap對象所構(gòu)建出來的對象
   */
  private void linkToParents(ResultSet rs, ResultMapping parentMapping, Object rowValue) throws SQLException {
    //將外鍵對應(yīng)結(jié)果集中的對象以及嵌套列名綁定到CacheKey對象中
    CacheKey parentKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getForeignColumn());
    //獲取該CacheKey對象對應(yīng)的PendingRelation列表
    List<PendingRelation> parents = pendingRelations.get(parentKey);
    //如果該列表不為null
    if (parents != null) {
      //遍歷PendingRelation列表
      for (PendingRelation parent : parents) {
        //如果列表中的每一項不為null 且 上一次嵌套的resultMap對象所構(gòu)建出來的對象也不為null
        if (parent != null && rowValue != null) {
          /**
           * 上一次嵌套的resultMap對象所構(gòu)建出來的對象放入元數(shù)據(jù)類型對象的相應(yīng)屬性中,如果為集合
           * 則在集合屬性中添加該rowValue;如果不為集合鲫趁,則直接將該屬性設(shè)置為rowValue
           */
          linkObjects(parent.metaObject, parent.propertyMapping, rowValue);
        }
      }
    }
  }

  /**
   * 添加 {@code parentMapping} 待定關(guān)系到待定關(guān)系映射集合 {@link #pendingRelations}
   * @param rs 結(jié)果集對象
   * @param metaResultObject 結(jié)果元對象
   * @param parentMapping 父級屬性映射
   */
  private void addPendingChildRelation(ResultSet rs, MetaObject metaResultObject, ResultMapping parentMapping) throws SQLException {
    //為多個結(jié)果數(shù)據(jù)創(chuàng)建緩存Key
    CacheKey cacheKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getColumn());
    //創(chuàng)建一個待定關(guān)系類對象
    PendingRelation deferLoad = new PendingRelation();
    //將結(jié)果元對象賦值到待定關(guān)系類對象中
    deferLoad.metaObject = metaResultObject;
    //將父級屬性映射賦值到待定關(guān)系類對象中
    deferLoad.propertyMapping = parentMapping;
    //從待定關(guān)系映射集合中獲取cacheKey對應(yīng)的待定關(guān)系集合斯嚎,如果沒有對應(yīng)的待定關(guān)系集合會新建一個集合返回出去。
    List<PendingRelation> relations = pendingRelations.computeIfAbsent(cacheKey, k -> new ArrayList<>());
    // issue #255
    //添加待定關(guān)系到集合中
    relations.add(deferLoad);
    //從之前整合的結(jié)果映射對象映射集合中獲取parentMapping.getResultSet()配置對應(yīng)結(jié)果映射
    ResultMapping previous = nextResultMaps.get(parentMapping.getResultSet());
    //如果沒有找對應(yīng)的結(jié)果映射
    if (previous == null) {
      //將結(jié)果映射加入到之前整合的結(jié)果映射對象映射集合中
      nextResultMaps.put(parentMapping.getResultSet(), parentMapping);
    } else {
      //如果獲取出來的映射結(jié)果和paraentMapping不是同一對象
      if (!previous.equals(parentMapping)) {
        //兩個不同的屬性不可以映射到相同的結(jié)果集
        throw new ExecutorException("Two different properties are mapped to the same resultSet");
      }
    }
  }

  /**
   * 為多個結(jié)果數(shù)據(jù)創(chuàng)建緩存Key
   * @param rs 結(jié)果集
   * @param resultMapping 結(jié)果屬性映射
   * @param names 列名
   * @param columns 列名
   * @return 對應(yīng)多個結(jié)果數(shù)據(jù)緩存Key
   */
  private CacheKey createKeyForMultipleResults(ResultSet rs, ResultMapping resultMapping, String names, String columns) throws SQLException {
    //新建一個緩存Key對象
    CacheKey cacheKey = new CacheKey();
    //將結(jié)果屬性映射作為緩存Key的一部分的
    cacheKey.update(resultMapping);
    //如果兩個列名參數(shù)都不為null
    if (columns != null && names != null) {
      //因為有可能指代多個列名挨厚,所以用逗號進(jìn)行分割
      String[] columnsArray = columns.split(",");
      ///因為有可能指代多個列名孝扛,所以用逗號進(jìn)行分割
      String[] namesArray = names.split(",");
      //遍歷列名數(shù)組
      for (int i = 0; i < columnsArray.length; i++) {
        //獲取列名對應(yīng)結(jié)果數(shù)據(jù)
        Object value = rs.getString(columnsArray[i]);
        if (value != null) {
          //將列名映射作為緩存Key的一部分的
          cacheKey.update(namesArray[i]);
          //將列名對應(yīng)結(jié)果數(shù)據(jù)作為緩存Key的一部分的
          cacheKey.update(value);
        }
      }
    }
    return cacheKey;
  }

  //
  // INSTANTIATION & CONSTRUCTOR MAPPING
  //

  /**
   * 根據(jù) {@code rsw} 和 {@code resultMap} 的配置構(gòu)建結(jié)果對象
   * @param rsw 結(jié)果集包裝類對象
   * @param resultMap Mapper.xml的resultMap標(biāo)簽信息封裝類對象
   * @param lazyLoader  用來表示需要懶加載的屬性集,本質(zhì)是一個HashMap
   * @param columnPrefix 列名前綴
   * @return {@link ResultMap#getType()} 類型的對象
   */
  private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    this.useConstructorMappings = false; // reset previous mapping result 重置上一個映射結(jié)果
    //構(gòu)造函數(shù)參數(shù)類型集合
    final List<Class<?>> constructorArgTypes = new ArrayList<>();
    //構(gòu)造函數(shù)參數(shù)集合
    final List<Object> constructorArgs = new ArrayList<>();
    //取得構(gòu)造函數(shù)所需的參數(shù)值去創(chuàng)建結(jié)果對象
    Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
    //如果結(jié)果對象不為null但沒有結(jié)果類型對應(yīng)的TypeHandler
    if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      //獲取屬性結(jié)果映射關(guān)系集合幽崩,該集合不包括標(biāo)記為構(gòu)造函數(shù)的結(jié)果映射關(guān)系
      final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
      //變量屬性結(jié)果映射關(guān)系
      for (ResultMapping propertyMapping : propertyMappings) {
        // issue gcode #109 && issue #149
        //如果配置了嵌套查詢而且還配置了該屬性為懶加載
        if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
          //將reusltObject改造成代理對象苦始,從而處理懶加載
          resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
          break;
        }
      }
    }
    //如果當(dāng)前結(jié)果對象不為null且構(gòu)造函數(shù)類型集合不為空,就將useConstructorMappings賦值為true
    this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping result 設(shè)置當(dāng)前結(jié)果映射關(guān)系
    return resultObject;
  }

  /**
   * 取得構(gòu)造函數(shù)所需的參數(shù)值去創(chuàng)建結(jié)果對象
   * @param rsw 結(jié)果集包裝類對象
   * @param resultMap Mapper.xml的resultMap標(biāo)簽信息封裝類對象
   * @param constructorArgTypes 構(gòu)造函數(shù)參數(shù)類型集合
   * @param constructorArgs 構(gòu)造函數(shù)參數(shù)集合
   * @param columnPrefix 列名前綴
   * @return {@link ResultMap#getType()} 類型的對象
   */
  private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
      throws SQLException {
    //獲取結(jié)果對象類型
    final Class<?> resultType = resultMap.getType();
    //構(gòu)建結(jié)果對象類型的元對象
    final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
    //獲取構(gòu)造函數(shù)映射關(guān)系
    final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
    //如果存在對應(yīng)的TypeHandler
    if (hasTypeHandlerForResultObject(rsw, resultType)) {
      //創(chuàng)建原始的結(jié)果對象
      return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
      //構(gòu)造函數(shù)映射關(guān)系不為空
    } else if (!constructorMappings.isEmpty()) {
      //根據(jù)構(gòu)造函數(shù)映射構(gòu)建的結(jié)果對象
      return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
      //如果resultType是接口或者resultType有默認(rèn)的構(gòu)造函數(shù)
    } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
      //讓objectFactory創(chuàng)建通過默認(rèn)構(gòu)造函數(shù)resultType對象
      return objectFactory.create(resultType);
      //是否可以應(yīng)用自動映射
    } else if (shouldApplyAutomaticMappings(resultMap, false)) {
      //取得構(gòu)造函數(shù)所需的參數(shù)值去創(chuàng)建結(jié)果對象(自動映射)
      return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs);
    }
    throw new ExecutorException("Do not know how to create an instance of " + resultType);
  }

  /**
   * 根據(jù)構(gòu)造函數(shù)映射構(gòu)建的結(jié)果對象
   * @param rsw 結(jié)果集包裝類對象
   * @param resultType 結(jié)果類型
   * @param constructorMappings  構(gòu)造函數(shù)參數(shù)映射關(guān)系集合
   * @param constructorArgTypes 構(gòu)造函數(shù)參數(shù)類型集合
   * @param constructorArgs 構(gòu)造函數(shù)參數(shù)集合
   * @param columnPrefix 列名前綴
   * @return 如果有構(gòu)建出構(gòu)造函數(shù)參數(shù)對象慌申,就讓objectFactory根據(jù)
   *        構(gòu)造函數(shù)參數(shù)創(chuàng)建resultType對象陌选,否則返回null
   */
  Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType, List<ResultMapping> constructorMappings,
                                         List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) {
    //有構(gòu)建出構(gòu)造函數(shù)參數(shù)對象的標(biāo)記
    boolean foundValues = false;
    //遍歷構(gòu)造函數(shù)參數(shù)映射關(guān)系
    for (ResultMapping constructorMapping : constructorMappings) {
      //獲取構(gòu)造函數(shù)參數(shù)映射關(guān)系對應(yīng)java類型
      final Class<?> parameterType = constructorMapping.getJavaType();
      //獲取構(gòu)造函數(shù)參數(shù)映射關(guān)系對應(yīng)的列名
      final String column = constructorMapping.getColumn();
      final Object value;
      try {
        //如果構(gòu)造函數(shù)參數(shù)映射關(guān)系配置了嵌套查詢的select標(biāo)簽ID
        if (constructorMapping.getNestedQueryId() != null) {
          //獲取嵌套查詢構(gòu)造函數(shù)參數(shù)值
          value = getNestedQueryConstructorValue(rsw.getResultSet(), constructorMapping, columnPrefix);
          //如果構(gòu)造函數(shù)參數(shù)映射關(guān)系配置了嵌套的resultMapId
        } else if (constructorMapping.getNestedResultMapId() != null) {
          //獲取構(gòu)造函數(shù)參數(shù)映射關(guān)系配置的resultMapId對應(yīng)的ResultMap對象
          final ResultMap resultMap = configuration.getResultMap(constructorMapping.getNestedResultMapId());
          //根據(jù)rsw 和 resultMap構(gòu)建出 {@link ResultMap#getType()} 類型的對象
          value = getRowValue(rsw, resultMap, getColumnPrefix(columnPrefix, constructorMapping));
          //不存在嵌套的情況
        } else {
          //獲取構(gòu)造函數(shù)參數(shù)映射的TypeHandler
          final TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
          //從 ResultSet 中取出columnName對應(yīng)數(shù)據(jù),然后轉(zhuǎn)換為 java 對象
          value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));
        }
      } catch (ResultMapException | SQLException e) {
        throw new ExecutorException("Could not process result for mapping: " + constructorMapping, e);
      }
      //將構(gòu)造函數(shù)參數(shù)類型添加到constructorArgTypes中
      constructorArgTypes.add(parameterType);
      //將構(gòu)造函數(shù)參數(shù)對象添加到construtorArgs中
      constructorArgs.add(value);
      //只要有一個構(gòu)造函數(shù)參數(shù)對象不為null咨油,foundValue都會為true
      foundValues = value != null || foundValues;
    }
    //如果有構(gòu)建出構(gòu)造函數(shù)參數(shù)對象法瑟,就讓objectFactory根據(jù)構(gòu)造函數(shù)參數(shù)創(chuàng)建resultType對象酥夭,否則返回null
    return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
  }


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子讲冠,更是在濱河造成了極大的恐慌疯攒,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蔚袍,居然都是意外死亡配名,警方通過查閱死者的電腦和手機(jī)啤咽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來渠脉,“玉大人宇整,你說我怎么就攤上這事∮蟊欤” “怎么了鳞青?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵霸饲,是天一觀的道長。 經(jīng)常有香客問我臂拓,道長厚脉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任胶惰,我火速辦了婚禮傻工,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘孵滞。我一直安慰自己中捆,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布坊饶。 她就那樣靜靜地躺著泄伪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪匿级。 梳的紋絲不亂的頭發(fā)上臂容,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機(jī)與錄音根蟹,去河邊找鬼脓杉。 笑死,一個胖子當(dāng)著我的面吹牛简逮,可吹牛的內(nèi)容都是我干的球散。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼散庶,長吁一口氣:“原來是場噩夢啊……” “哼淆游!你這毒婦竟也來了锡凝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎悴能,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崖疤,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡仰冠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了轻腺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乐疆。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖贬养,靈堂內(nèi)的尸體忽然破棺而出挤土,到底是詐尸還是另有隱情,我是刑警寧澤误算,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布仰美,位于F島的核電站迷殿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏咖杂。R本人自食惡果不足惜庆寺,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望翰苫。 院中可真熱鬧止邮,春花似錦、人聲如沸奏窑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽埃唯。三九已至撩匕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間墨叛,已是汗流浹背止毕。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留漠趁,地道東北人扁凛。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像闯传,于是被迫代替她去往敵國和親谨朝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容