Mybatis的結果集處理

此時咱們已經能夠把整段的SQL語句取出,但還並無在數據庫中去執行,咱們能夠先來分析一下配置文件中SQL語句執行後的結果集是如何處理的。java

Mybatis會將結果集按照映射配置文件中定義的映射規則,例如<resultMap>,resultType屬性等,映射成相應的結果對象。mysql

在StatementHandler接口執行完指定的select語句以後,會將查詢獲得的結果集交給ResultSetHandler完成映射處理。ResultSetHandler除了負責映射select語句查詢獲得的結果集,還會處理存儲過程執行後的輸出參數。ResultSetHandler是一個接口,定義以下sql

public interface ResultSetHandler {
  //處理結果集,生成相應的結果對象集合
  <E> List<E> handleResultSets(Statement stmt) throws SQLException;
  //處理結果集,返回相應的遊標對象
  <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
  //處理存儲過程的輸出參數
  void handleOutputParameters(CallableStatement cs) throws SQLException;

}

ResultSetHandler只有一個實現類DefaultResultSetHandler,其核心字段以下數據庫

private final Executor executor;  //執行器對象
private final Configuration configuration; //全局配置信息對象
private final MappedStatement mappedStatement; //記錄了SQL語句節點全部信息的對象(<select><insert><update>節點等)
private final RowBounds rowBounds; //邏輯分頁對象(不一樣於SQL語句中的limit物理分頁)
private final ParameterHandler parameterHandler; //參數處理器
private final ResultHandler<?> resultHandler; //用戶指定用於處理結果集的ResultHandler對象
private final BoundSql boundSql; //SqlSource執行後返回的包含完整SQL語句的對象
private final TypeHandlerRegistry typeHandlerRegistry; //類型處理器註冊器
private final ObjectFactory objectFactory; //對象工廠
private final ReflectorFactory reflectorFactory; //反射工廠
private final Map<CacheKey, Object> nestedResultObjects = new HashMap<CacheKey, Object>(); //嵌套的resultMap對象映射
private Object previousRowValue; //上一次嵌套的resultMap對象
//PendingRelation是DefaultResultSetHandler的內部靜態類,記錄了當前結果對象對應的MetaObject對象以及parentMapping對象
//該對象就爲CacheKey對象跟所有的PendingRelation對象的映射
private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<CacheKey, List<PendingRelation>>();

經過select語句查詢數據庫獲得的結果集由其handlerResultSets()方法進行處理。該方法不只能夠處理Statement,PreparedStatement產生的結果集,還能夠處理CallableStatement調用存儲過程產生的多結果集。例如以下存儲過程,就會產生多個ResultSet對象。數組

CREATE PROCEDURE test_proc()mybatis

BEGINapp

        select * from persion;ide

        select * from item;ui

END;this

handleResultSets()方法以下

@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;
  //獲取第一個ResultSet對象,可能存在多個ResultSet
  ResultSetWrapper rsw = getFirstResultSet(stmt);
  //獲取MappedStatement.resultMaps集合,映射文件中的<resultMap>節點會被解析成ResultMap對象,保存到MappedStatement.resultMaps集合中
  //若是SQL節點可以產生多個ResultSet,那麼咱們能夠在SQL節點的resultMap屬性中配置多個<resultMap>節點的id,它們之間經過","分隔,實現對多個
  //結果集的映射
  List<ResultMap> resultMaps = mappedStatement.getResultMaps();
  int resultMapCount = resultMaps.size();
  //若是結果集不爲null,則resultMaps集合(List)不能爲空,不然拋出異常
  validateResultMapsCount(rsw, resultMapCount);
  //遍歷resultMaps集合
  while (rsw != null && resultMapCount > resultSetCount) {
    //取出resultMaps集合中的每個ResultMap對象
    ResultMap resultMap = resultMaps.get(resultSetCount);
    handleResultSet(rsw, resultMap, multipleResults, null);
    rsw = getNextResultSet(stmt);
    cleanUpAfterHandlingResultSet();
    resultSetCount++;
  }

  String[] resultSets = mappedStatement.getResultSets();
  if (resultSets != null) {
    while (rsw != null && resultSetCount < resultSets.length) {
      ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
      if (parentMapping != null) {
        String nestedResultMapId = parentMapping.getNestedResultMapId();
        ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
        handleResultSet(rsw, resultMap, null, parentMapping);
      }
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }
  }

  return collapseSingleResultList(multipleResults);
}
private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
  //Statement是JDBC數據操做的接口,由Connection鏈接數據庫後建立,由各類不一樣的數據庫驅動來建立實現類,因爲咱們項目最近使用的是mysql 8版本的數據庫,它的實現類已經跟
  //以往的mysql版本大不相同,此處爲獲取結果集
  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)
    //檢測是否還有待處理的ResultSet
    if (stmt.getMoreResults()) {
      rs = stmt.getResultSet();
    } else {
      if (stmt.getUpdateCount() == -1) { //沒有待處理的ResultSet
        // no more results. Must be no resultset
        break;
      }
    }
  }
  //將結果集封裝成ResultSetWrapper對象
  return rs != null ? new ResultSetWrapper(rs, configuration) : null;
}
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 {
    //若是ResultMapping對象不爲null
    if (parentMapping != null) {
      handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
    } else {
      if (resultHandler == null) {
        DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
        handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
        multipleResults.add(defaultResultHandler.getResultList());
      } else {
        handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
      }
    }
  } finally {
    // issue #228 (close resultsets)
    closeResultSet(rsw.getResultSet());
  }
}
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
  //該resultMap是否存在嵌套
  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 handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
  //默認上下文對象
  final DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
  //將結果集移動到分頁處
  skipRows(rsw.getResultSet(), rowBounds);
  //獲取上一次嵌套的resultMap對象
  Object rowValue = previousRowValue;
  //若是已處理的結果集還未到達上限且結果集中還有能夠處理的記錄,進入循環
  while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
    //獲取全部嵌套中的最終resultMap對象
    final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
    //將該resultMap對象中的元素構建成CacheKey對象
    final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
    //從嵌套的resultMap映射中查找該CacheKey對象映射的resultMap對象
    Object partialObject = nestedResultObjects.get(rowKey);
    //若是<select>標籤嵌套或者分組了
    if (mappedStatement.isResultOrdered()) {
      //若是嵌套映射中沒有該resultMap對象且上一次嵌套的resultMap對象不爲null
      if (partialObject == null && rowValue != null) {
        //清空嵌套resultMap映射
        nestedResultObjects.clear();
        //
        storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
      }
      rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
    } else {
      rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
      if (partialObject == null) {
        storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
      }
    }
  }
  if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) {
    storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
    previousRowValue = null;
  } else if (rowValue != null) {
    previousRowValue = rowValue;
  }
}
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 {
    //依次訪問結果集直到分頁對象的偏移量處
    for (int i = 0; i < rowBounds.getOffset(); i++) {
      rs.next();
    }
  }
}
private boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) throws SQLException {
  //返回已經處理的行數是否到達分頁的上限
  return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
}
public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException {
  //記錄已經處理過的ResultMap的id
  Set<String> pastDiscriminators = new HashSet<String>();
  //獲取<resultMap>中的<discriminator>節點對象,discriminator是一個鑑別器節點,如下有關於鑑別器節點的說明
  Discriminator discriminator = resultMap.getDiscriminator();
  //當該鑑別器對象不爲null時,進入循環
  while (discriminator != null) {
    //獲取記錄中對應列的值,其中會使用相應的類型處理器對象將該列值轉換成java類型
    final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);
    //根據該列值獲取對應的ResultMap的id,由於這裏是處理嵌套的狀況,因此在<discriminator>節點下又有<resultMap>節點,若是不嵌套就通常是
    //<result>或者<id>節點
    final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));
    //查找全局配置信息中是否有該嵌套的resultMap節點的id
    if (configuration.hasResultMap(discriminatedMapId)) {
      //若是有該id,根據該id在全局配置信息中獲取該resultMap對象
      resultMap = configuration.getResultMap(discriminatedMapId);
      //記錄當前鑑別器對象
      Discriminator lastDiscriminator = discriminator;
      //獲取resultMap對象中的鑑別器對象
      discriminator = resultMap.getDiscriminator();
      //檢測鑑別器是否出現了環形引用
      if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {
        break;
      }
    } else {
      break;
    }
  }
  //返回全部嵌套中最終的使用的resultMap
  return resultMap;
}

鑑別器節點的說明

<!-- =======================鑑別器============================ -->
    <!-- <discriminator javaType=""></discriminator>
        鑑別器:mybatis可使用discriminator判斷某列的值,而後根據某列的值改變封裝行爲
        封裝Employee:
            若是查出的是女生:就把部門信息查詢出來,不然不查詢;
            若是是男生,把last_name這一列的值賦值給email;
     -->
     <resultMap type="com.mybatis.bean.Employee" id="MyEmpDis">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
        <!--
            column:指定斷定的列名
            javaType:列值對應的java類型  -->
        <discriminator javaType="string" column="gender">
            <!--女生  resultType:指定封裝的結果類型;不能缺乏。/resultMap-->
            <case value="0" resultType="com.atguigu.mybatis.bean.Employee">
                <association property="dept"
                    select="com.mybatis.dao.DepartmentMapper.getDeptById"
                    column="d_id">
                </association>
            </case>
            <!--男生 ;若是是男生,把last_name這一列的值賦值給email; -->
            <case value="1" resultType="com.mybatis.bean.Employee">
                <id column="id" property="id"/>
                <result column="last_name" property="lastName"/>
                <result column="last_name" property="email"/>
                <result column="gender" property="gender"/>
            </case>
        </discriminator>
     </resultMap>

private Object getDiscriminatorValue(ResultSet rs, Discriminator discriminator, String columnPrefix) throws SQLException {
  //獲取鑑別器的resultMapping對象
  final ResultMapping resultMapping = discriminator.getResultMapping();
  //獲取resultMapping對象的類型處理器對象
  final TypeHandler<?> typeHandler = resultMapping.getTypeHandler();
  //使用類型處理器來處理從所有結果集中獲取columnPrefix+resultMapping.getColumn()爲列名的Java對象
  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;
}
private CacheKey createRowKey(ResultMap resultMap, ResultSetWrapper rsw, String columnPrefix) throws SQLException {
  //建立CacheKey對象
  final CacheKey cacheKey = new CacheKey();
  //將resultMap的id做爲Cachekey對象的一部分
  cacheKey.update(resultMap.getId());
  //查找ResultMapping對象集合
  List<ResultMapping> resultMappings = getResultMappingsForRowKey(resultMap);
  //若是該ResultMapping對象集合爲空
  if (resultMappings.isEmpty()) {
    //若是ResultMap對象爲Map接口的實現類
    if (Map.class.isAssignableFrom(resultMap.getType())) {
      //由結果集中的全部列名以及當前記錄行的全部列值一塊兒構成CacheKey對象
      createRowKeyForMap(rsw, cacheKey);
    //若是ResultMap對象不是Map接口的實現類
    } else {
      //由結果集中未映射的列名以及它們在當前記錄中的對應列值一塊兒構成CacheKey對象
      createRowKeyForUnmappedProperties(resultMap, rsw, cacheKey, columnPrefix);
    }
  //若是該ResultMapping對象集合不爲空
  } else {
    //由resultMappings集合中的列名以及它們在當前記錄行中相應的列值一塊兒構成CacheKey
    createRowKeyForMappedProperties(resultMap, rsw, cacheKey, resultMappings, columnPrefix);
  }
  //若是經過上面的查找沒有找到任何列參與構成CacheKey對象,則返回NULL_CACHE_KEY對象
  if (cacheKey.getUpdateCount() < 2) {
    return CacheKey.NULL_CACHE_KEY;
  }
  return cacheKey;
}
private List<ResultMapping> getResultMappingsForRowKey(ResultMap resultMap) {
  //從resultMap對象中獲取idResultMappings集合,該集合記錄<idArg>、<id>節點對應的ResultMapping對象
  List<ResultMapping> resultMappings = resultMap.getIdResultMappings();
  //若是該集合爲空
  if (resultMappings.isEmpty()) {
    //獲取resultMap對象中記錄了除<id*>節點以外的ResultMapping對象
    resultMappings = resultMap.getPropertyResultMappings();
  }
  return resultMappings;
}
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);
    //若是該值不爲null
    if (value != null) {
      //將列名與值分別做爲cacheKey的一部分
      cacheKey.update(columnName);
      cacheKey.update(value);
    }
  }
}
private void createRowKeyForUnmappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, String columnPrefix) throws SQLException {
  //獲取resultMap對象的反射原類型對象(包含類全部的方法,屬性,構造器等等)
  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;
      }
    }
    //若是ResultMap類中有該屬性
    if (metaType.findProperty(property, configuration.isMapUnderscoreToCamelCase()) != null) {
      //從結果集中獲取該列名對應的值
      String value = rsw.getResultSet().getString(column);
      //若是該值不爲null
      if (value != null) {
        //將列名與值分別做爲cacheKey的一部分
        cacheKey.update(column);
        cacheKey.update(value);
      }
    }
  }
}
private void createRowKeyForMappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, List<ResultMapping> resultMappings, String columnPrefix) throws SQLException {
  //遍歷resultMappings集合
  for (ResultMapping resultMapping : resultMappings) {
    //若是resultMapping對象獲取的嵌套ResultMap的id不爲null而獲取的結果集爲null
    if (resultMapping.getNestedResultMapId() != null && resultMapping.getResultSet() == null) {
      // Issue #392
      //從全局配置信息中獲取該id對應的ResultMap對象
      final ResultMap nestedResultMap = configuration.getResultMap(resultMapping.getNestedResultMapId());
      //遞歸該嵌套ResultMap對象
      createRowKeyForMappedProperties(nestedResultMap, rsw, cacheKey, nestedResultMap.getConstructorResultMappings(),
          prependPrefix(resultMapping.getColumnPrefix(), columnPrefix));
    //若是resultMapping對象的嵌套查詢id爲null
    } else if (resultMapping.getNestedQueryId() == null) {
      //拼裝columnPrefix+resultMapping.getColumn()爲column字符串
      final String column = prependPrefix(resultMapping.getColumn(), columnPrefix);
      //獲取resultMapping的類型處理器對象
      final TypeHandler<?> th = resultMapping.getTypeHandler();
      //獲取結果集的映射列名集合
      List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
      // Issue #114
      //若是column不爲null且列名集合中包含轉換爲大寫的column
      if (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) {
        //經過類型處理器獲取結果集中該column對應的Java對象(值)
        final Object value = th.getResult(rsw.getResultSet(), column);
        //若是該值不爲null或者全局配置信息中容許返回空實例
        if (value != null || configuration.isReturnInstanceForEmptyRow()) {
          //將列名與值分別做爲cacheKey的一部分
          cacheKey.update(column);
          cacheKey.update(value);
        }
      }
    }
  }
}
private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
  //若是上一層的ResultMapping對象不爲null
  if (parentMapping != null) {
    //將嵌套對象記錄到外層元對象相應的屬性中
    linkToParents(rs, parentMapping, rowValue);
  //若是上一層的ResultMapping對象爲null
  } else {
    callResultHandler(resultHandler, resultContext, rowValue);
  }
}

假設有這麼一段resultMap

<resultMap id="blogResult" type="Blog">
  <id property="id" column="id" />
  <result property="title" column="title"/>
  <association property="author" javaType="Author" resultSet="authors" column="author_id" foreignColumn="id">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="password" column="password"/>
    <result property="email" column="email"/>
    <result property="bio" column="bio"/>
  </association>
</resultMap>

private void linkToParents(ResultSet rs, ResultMapping parentMapping, Object rowValue) throws SQLException {
  //將外鍵對應結果集中的對象以及嵌套列名綁定到CacheKey對象中
  CacheKey parentKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getForeignColumn());
  //獲取該CacheKey對象對應的PendingRelation列表
  List<PendingRelation> parents = pendingRelations.get(parentKey);
  //若是該列表不爲null
  if (parents != null) {
    //遍歷該列表
    for (PendingRelation parent : parents) {
      //若是列表中的每一項不爲null且上一次嵌套的resultMap對象也不爲null
      if (parent != null && rowValue != null) {
        //將上一層嵌套的resultMap對象放入元數據類型對象的相應屬性中,若是爲集合則在集合屬性中添加該rowValue;若是不爲集合,則直接將該屬性設置爲rowValue
        linkObjects(parent.metaObject, parent.propertyMapping, rowValue);
      }
    }
  }
}
private CacheKey createKeyForMultipleResults(ResultSet rs, ResultMapping resultMapping, String names, String columns) throws SQLException {
  //新建CacheKey對象
  CacheKey cacheKey = new CacheKey();
  //將resultMapping對象綁定到cachekey中
  cacheKey.update(resultMapping);
  //若是該resultMapping的ForeignColumn屬性和Column屬性都不爲null
  if (columns != null && names != null) {
    //以","爲分隔符截取ForeignColumn爲字符串數組
    String[] columnsArray = columns.split(",");
    //以","爲分隔符截取Clounmn爲字符串數組
    String[] namesArray = names.split(",");
    //遍歷ForeignColumn字符串數組
    for (int i = 0; i < columnsArray.length; i++) {
      //獲取字符串數組中的每一項在結果集中對象
      Object value = rs.getString(columnsArray[i]);
      //若是該對象不爲null
      if (value != null) {
        //將Columns字符串數組中的每一項以及ForeignColumns中每一項對應結果集中的對象綁定到cachekey中
        cacheKey.update(namesArray[i]);
        cacheKey.update(value);
      }
    }
  }
  return cacheKey;
}
private void linkObjects(MetaObject metaObject, ResultMapping resultMapping, Object rowValue) {
  //檢查上一層的resultMapping是否爲集合,若是爲集合則進行實例化返回
  final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
  //若是返回的集合對象不爲null
  if (collectionProperty != null) {
    //根據該集合對象在全局配置信息中生成元數據類型對象
    final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
    //元數據類型對象的對象包裝器屬性(集合)中添加上一層的resultMap對象
    targetMetaObject.add(rowValue);
  } else {
    //若是返回的集合對象爲null,表示resultMapping對象不爲集合,直接將上一層的resultMap對象設置進元數據對象的resultMapping.getProperty()屬性中
    metaObject.setValue(resultMapping.getProperty(), rowValue);
  }
}
private Object instantiateCollectionPropertyIfAppropriate(ResultMapping resultMapping, MetaObject metaObject) {
  //獲取resultMapping對象的Property屬性
  final String propertyName = resultMapping.getProperty();
  //從metaObject中獲取resultMapping對象所對應的Java對象中該屬性的值(metaObject與metaClass不一樣,metaClass保存了類的全部屬性,方法;metaObject保存了對象全部屬性
  //的值)
  Object propertyValue = metaObject.getValue(propertyName);
  //若是該值爲null
  if (propertyValue == null) {
    //獲取resultMapping對象的Java類實例
    Class<?> type = resultMapping.getJavaType();
    //若是該類實例爲null(在配置文件中沒寫)
    if (type == null) {
      //從metaObject中獲取該屬性的Java類實例
      type = metaObject.getSetterType(propertyName);
    }
    try {
      //若是該java類實例爲一個集合類型
      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);
    }
  //若是該值不爲null,且該值的類實例爲集合類型
  } else if (objectFactory.isCollection(propertyValue.getClass())) {
    //返回該值
    return propertyValue;
  }
  return null;
}
private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {
  resultContext.nextResultObject(rowValue);
  ((ResultHandler<Object>) resultHandler).handleResult(resultContext);
}

在DefaultObjectFactory中

@Override
public <T> boolean isCollection(Class<T> type) {
  //返回type是不是Collection接口的實現類或子接口
  return Collection.class.isAssignableFrom(type);
}
@Override
public <T> T create(Class<T> type) {
  return create(type, null, null);
}
@SuppressWarnings("unchecked")
@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
  //獲取接口的實現類實例
  Class<?> classToCreate = resolveInterface(type);
  //返回該接口的實現類的實例化對象
  return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
}
protected Class<?> resolveInterface(Class<?> type) {
  //實現類
  Class<?> classToCreate;
  //若是該接口爲List,Collection,Iterable
  if (type == List.class || type == Collection.class || type == Iterable.class) {
    //實現類定爲ArrayList
    classToCreate = ArrayList.class;
  //若是該接口爲Map
  } else if (type == Map.class) {
    //實現類定爲HashMap
    classToCreate = HashMap.class;
  //若是該接口爲SortedSet
  } else if (type == SortedSet.class) { // issue #510 Collections Support
    //實現類定爲TreeSet
    classToCreate = TreeSet.class;
  //若是接口爲Set
  } else if (type == Set.class) {
    //實現類定爲HashSet
    classToCreate = HashSet.class;
  //若是不是集合接口
  } else {
    //直接獲取該類
    classToCreate = type;
  }
  return classToCreate;
}
private  <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
  try {
    //定義構造器
    Constructor<T> constructor;
    //若是構造參數類型列表或者構造參數對象列表爲null
    if (constructorArgTypes == null || constructorArgs == null) {
      //獲取該類實例的無參構造器
      constructor = type.getDeclaredConstructor();
      //若是該構造器沒有私有成員訪問標誌
      if (!constructor.isAccessible()) {
        //設置該構造器能夠訪問私有成員
        constructor.setAccessible(true);
      }
      //返回該構造器進行無參構造的對象實例
      return constructor.newInstance();
    }
    //若是構造參數類型列表或者構造參數對象列表不全爲null,獲取該類實例的以構造參數類型列表爲構造參數的有參構造器
    constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
    if (!constructor.isAccessible()) {
      constructor.setAccessible(true);
    }
    //返回該構造器進行有參構造的對象實例
    return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
  } catch (Exception e) {
    //異常處理
    StringBuilder argTypes = new StringBuilder();
    if (constructorArgTypes != null && !constructorArgTypes.isEmpty()) {
      for (Class<?> argType : constructorArgTypes) {
        argTypes.append(argType.getSimpleName());
        argTypes.append(",");
      }
      argTypes.deleteCharAt(argTypes.length() - 1); // remove trailing ,
    }
    StringBuilder argValues = new StringBuilder();
    if (constructorArgs != null && !constructorArgs.isEmpty()) {
      for (Object argValue : constructorArgs) {
        argValues.append(String.valueOf(argValue));
        argValues.append(",");
      }
      argValues.deleteCharAt(argValues.length() - 1); // remove trailing ,
    }
    throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
}
}
相關文章
相關標籤/搜索