欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MyBatis?handleResultSet結(jié)果集解析過程示例

 更新時(shí)間:2023年02月16日 14:40:07   作者:念念清晰  
這篇文章主要為大家介紹了MyBatis?handleResultSet結(jié)果集解析過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前置知識

mybatis版本: 3.5.12

之前說到mybatis執(zhí)行完SQL后的結(jié)果集是由DefaultResultHandler組件的handleResultSets處理的。今天就來探討下這個(gè)重要的方法,該方法非常核心,而且內(nèi)容比較多,所以單拎出來一章。而上文DefaultResultHandler處理結(jié)果集的大致流程請參考:MyBatis ResultSetHandler 結(jié)果集的解析過程

在理解handleResultSets是怎么對結(jié)果集進(jìn)行處理時(shí),需要明白MyBatis中這么幾個(gè)組件

  • ResultMap和ResultMapping
  • ResultHandler和ResultContext
  • ResultLoaderMap和ResultLoader(這些是延時(shí)加載相關(guān))
  • ProxyFactory(延時(shí)加載相關(guān),用來為延時(shí)加載對象創(chuàng)建代理對象使用的)

ResultMap和ResultMapping

我們經(jīng)常使用MyBatis的xml文件配置SQL信息,在select標(biāo)簽上有一個(gè)屬性是resultMap,它會指向一個(gè)resultMap標(biāo)簽,resultMap標(biāo)簽示例如下

<resultMap id="usermap" type="user" autoMapping="true">
    <!--關(guān)閉自動映射,那么沒有指定的列名不會出現(xiàn)在結(jié)果集中-->
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="birthday" column="birthday"/>
    <result property="password" column="password"/>
</resultMap>

mybatis中每個(gè)resultMap標(biāo)簽會被解析成ResultMap對象。而resultMap標(biāo)簽中的idresultconstructor這3種子標(biāo)簽會被解析成ResultMapping對象(id其實(shí)就是特殊的result標(biāo)簽)。

接下來我們來看下ResultMap的重要組成部分

public class ResultMap {
  private Configuration configuration;
  // 唯一ID,一般是namespace+resultMap標(biāo)簽的ID
  private String id;
  // 對應(yīng)的Java類型
  private Class<?> type;
  // resultMap標(biāo)簽中的result標(biāo)簽的集合
  private List<ResultMapping> resultMappings;
  // resultMap標(biāo)簽中的id標(biāo)簽的集合
  private List<ResultMapping> idResultMappings;
  // resultMap標(biāo)簽中的constructor標(biāo)簽的集合
  private List<ResultMapping> constructorResultMappings;
  // resultMap標(biāo)簽中所有子標(biāo)簽的集合
  private List<ResultMapping> propertyResultMappings;
  // 結(jié)果集中列名
  private Set<String> mappedColumns;
  // 對應(yīng)的Java對象的屬性名
  private Set<String> mappedProperties;
  // discriminator鑒別器會單獨(dú)被解析成該對象
  private Discriminator discriminator;
  // 是否是嵌套映射
  private boolean hasNestedResultMaps;
  // 是否嵌套查詢
  private boolean hasNestedQueries;
  // 是否自動映射
  private Boolean autoMapping;
}

其中比較重要的幾個(gè)屬性就是

  • resultMappings:它表示resultMap標(biāo)簽中的result標(biāo)簽的集合(包含id標(biāo)簽)后續(xù)結(jié)果集的解析過程避免不了會遍歷它
  • hasNestedResultMaps:是否由嵌套映射,一般都是resumtMap標(biāo)簽中含有collection標(biāo)簽association標(biāo)簽才會為true,后面介紹到嵌套映射會分析。

ResultHandler和ResultContext

在mybatis的解析過程中,我們很容易想象到它是遍歷結(jié)果集然后和resultMap標(biāo)簽的映射關(guān)系進(jìn)行比較,最終生成結(jié)果集對象。那么遍歷結(jié)果集其實(shí)就是對一條一條數(shù)據(jù)進(jìn)行單獨(dú)處理。處理完一條記錄,就把這條記錄對應(yīng)的對象添加到一個(gè)集合中,最終獲取這個(gè)集合就是用戶想要得到的對象。

ResultContext用來在上下文中傳遞解析過后的單個(gè)對象,ResultHandler內(nèi)部有一個(gè)List集合用來存儲單條數(shù)據(jù)解析后的對象的。他們的源碼非常簡單易懂,首先我們來看DefaultResultHandler(ResultHandler的實(shí)現(xiàn)類)的源碼

public class DefaultResultHandler implements ResultHandler<Object> {
  private final List<Object> list;
  @Override
  public void handleResult(ResultContext<?> context) {
    list.add(context.getResultObject());
  }
  public List<Object> getResultList() {
    return list;
  }
}

它只有一個(gè)屬性list,list就是用來存儲解析單條數(shù)據(jù)后的對象。它還提供了兩個(gè)方法

  • handleResult:就是把上下文中單條數(shù)據(jù)處理后的對象存入到list集合中。
  • getResultList:獲取結(jié)果集解析過后的list,也就是用戶最終需要的list對象。

接下來來看下ResultContext這個(gè)上下文對象

public class DefaultResultContext<T> implements ResultContext<T> {
  private T resultObject;
  private int resultCount;
  private boolean stopped;
  public T getResultObject() {
    return resultObject;
  }
  public void nextResultObject(T resultObject) {
    resultCount++;
    this.resultObject = resultObject;
  }
}

它由三個(gè)屬性:

  • resultObject:用來保存當(dāng)前解析的這條記錄的結(jié)果
  • resultCount:結(jié)果集的數(shù)量,每解析完一條記錄,該值加一
  • stopped:是否停止解析,當(dāng)?shù)阶詈笠粭l記錄時(shí),該值為false

它的兩個(gè)方法比較簡單,就不再說了。

接下來我們正式進(jìn)入mybatis解析結(jié)果集的核心代碼分析。mybatis解析結(jié)果集可以分為兩大類:一是簡單映射、而是嵌套映射。接下來我們即從這兩個(gè)方面研究

簡單映射

接下來就來看下本文主題handleResultSet方法的核心邏輯

private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
    if (parentMapping != null) {
      // 1. 處理resultSets標(biāo)簽的邏輯
      handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
    } else {
      // 2. 正常處理resultMap標(biāo)簽。將結(jié)果集中的記錄映射為指定對象??赡苌婕暗角短子成?。
      if (resultHandler == null) {
        // 默認(rèn)都會走進(jìn)該分支。
        // ResultSet是個(gè)集合嘛,那Result自然就是集合中的一條記錄啦。DefaultResultHandler是用來處理單條Result記錄的。
        DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
        // 處理多行記錄的方法(重要?。。。。。。。?
        handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
        multipleResults.add(defaultResultHandler.getResultList());
      } else {
        // 如果用戶自定義了 resultHandler 使用用戶自定義的
        handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
      }
    }
}

這個(gè)方法簡介明了,它的執(zhí)行流程是這樣的:

第一步:判斷parentMapping是否存在值。而這個(gè)分支是專門為解析resultSets標(biāo)簽使用的分支,其實(shí)和普通的解析結(jié)果集沒什么不同。等看完后面的解析過程再回過頭看就理解了。這個(gè)分支不重要,我們繼續(xù)往下走

第二步:判斷用戶是否指定resultHandler類型,一般都是不會指定的,所以他會走第一個(gè)分支。創(chuàng)建一個(gè)默認(rèn)的ResultHandler,然后執(zhí)行handleRowValues方法

第三步:如果用戶指定resultHandler類型,就執(zhí)行handleRowValues方法

可以發(fā)現(xiàn)無論是哪個(gè)分支,最終都會走到handleRowValues方法,從名字也能看出,該方法的邏輯是處理多行數(shù)據(jù)。接下來我們就來看下DefaultResultSetHandler#handleRowValues方法

handleRowValues

public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler&lt;?&gt; 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);
  }
}

該方法只做了一件事情,那就是判斷結(jié)果集是否是嵌套映射的。這取決于xml文件中resultMap標(biāo)簽是否定義了collectionassociation標(biāo)簽。這里我們先討論簡單映射的場景。所以接下來我們來看DefaultResultSetHandler#handleRowValuesForSimpleResultMap方法。從名字也可以看出,該方法的邏輯是處理簡單映射。簡單映射不會涉及延遲加載等復(fù)雜的邏輯,所以源碼很好理解

handleRowValuesForSimpleResultMap

private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
    throws SQLException {
  // 第一步:經(jīng)過resultHandler處理過后,每行記錄會被映射成一個(gè)對象。該對象暫存在 這個(gè)Result上下文中。(暫存DefaultResultContext)
  DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
  ResultSet resultSet = rsw.getResultSet();
  // 跳過指定的偏移量,相當(dāng)于limit只不過他是內(nèi)存分頁,一般用不到(RowBounds中指定的偏移量)
  skipRows(resultSet, rowBounds);
  // 第二步:結(jié)果集中會有很多記錄,通過該循環(huán)處理結(jié)果集中的每條記錄。每個(gè)記錄最后都會存儲到ResultHandler的List集合中。
  while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
    // 處理discrimination標(biāo)簽。類似于Java中的switch語法。如果resultMap標(biāo)簽有鑒別器。則根據(jù)case的情況動態(tài)的獲取resultMap映射結(jié)果集
    ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
    // 第三步:獲取記錄映射的對象(重要?。。。。。。?
    Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
    // 第四步:把對象存儲到上下文中。
    storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
  }
}

下面是該方法的執(zhí)行邏輯

第一步:定義ResultContext對象(前文說過),它用來暫存每一行記錄的處理結(jié)果的對象。從ResultSetWrapper中獲取JDBC的結(jié)果集對象ResultSet。skipRows方法跳過指定的內(nèi)存分頁(一般沒什么用,忽略該方法即可,研究價(jià)值不大)

第二步:遍歷結(jié)果集,通過resolveDiscriminatedResultMap方法得到鑒別器鑒別的ResultMap對象,其實(shí)本質(zhì)上還是一個(gè)ResultMap(有關(guān)鑒別器的內(nèi)容請參考另一篇文章:MyBatis discriminator標(biāo)簽 實(shí)戰(zhàn)和原理解析

第三步:調(diào)用getRowValue方法處理每一行數(shù)據(jù)并得到結(jié)果對象

第四步:把上一步生成的對象通過上下文ResultContext添加到ResultHandler中。(再次提示:ResultHandler對象里面存放結(jié)果集解析后的對象集合哦)

其中,重點(diǎn)操作在第三步和第四步。接下來我們就先來聊聊getRowValue方法是如何處理一行記錄的。

getRowValue

private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
  final ResultLoaderMap lazyLoader = new ResultLoaderMap();
  // (重要方法?。。。。。。。。。。。。┍热绶祷亟Y(jié)果ResultType指定的是map,那么這里就會創(chuàng)建一個(gè)空Map對象,下面的if才是給map里添加元素。
  Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
  if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
    final MetaObject metaObject = configuration.newMetaObject(rowValue);
    boolean foundValues = this.useConstructorMappings;
    if (shouldApplyAutomaticMappings(resultMap, false)) {
      // (重要方法?。。。。。。。。。。。。┦欠駪?yīng)該自動映射。比如說SQL返回結(jié)果集有10列,但是resultMap只配置了9個(gè)字段,剩下的那個(gè)字段,如果滿足返回列與映射列名稱相同,就會自動進(jìn)行映射
      foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
    }
    // (重要方法?。。。。。。。。。。。。┨幚韗esultMap標(biāo)簽中的映射。把結(jié)果集根據(jù)resultMap中的映射關(guān)系生成最終的結(jié)果對象。屬性會被設(shè)置到metaObject中
    foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
    foundValues = lazyLoader.size() > 0 || foundValues;
    // isReturnInstanceForEmptyRow是否啟用。如果開啟則返回空對象,否則返回null。
    // 注:這個(gè)空對象依賴于createResultObject方法創(chuàng)建出的對象是空還是null。
    rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
  }
  return rowValue;
}

該方法處理邏輯如下(延時(shí)加載的代碼請忽略,簡單映射不會涉及到延時(shí)加載,這里之所以會出現(xiàn)ResultLoaderMap這樣延時(shí)加載相關(guān)的對象,是因?yàn)榍短子成浞椒ㄒ矔{(diào)用這個(gè)方法解析結(jié)果集。)

第一步:首先通過createResultObject對象創(chuàng)建一個(gè)空殼對象,啥是空殼對象呢?比如說xml文件中的resultMap標(biāo)簽定義了返回值類型是User類型,那么這里就會創(chuàng)建一個(gè)User對象,但是屬性值全為空。

當(dāng)然createResultObject背后的邏輯其實(shí)很復(fù)雜,它會首先判斷用戶是否在resultMap標(biāo)簽中定義了構(gòu)造器標(biāo)簽,如果沒定義才會按上述流程描述所說的創(chuàng)建一個(gè)空殼對象。但如果用戶在resultMap標(biāo)簽中定義了構(gòu)造器標(biāo)簽,那么就會直接將結(jié)果集中的數(shù)據(jù)通過構(gòu)造器構(gòu)造出完整的對象。這樣也很能理解嗎,畢竟調(diào)用構(gòu)造器是要傳值的。

第二步:通過applyAutomaticMappings方法完成自動映射,啥是自動映射嘞。比如一條sql返回的列由name age兩列,但是resultMap標(biāo)簽中只定義了一個(gè)映射關(guān)系name,那么age列就會自動尋找映射關(guān)系,如果發(fā)現(xiàn)列名age與resultMap返回類型的屬性同名,就會自動映射到該類型中。該步驟中只會映射resultMap標(biāo)簽中未定義的映射關(guān)系對應(yīng)的字段

第三步:通過applyPropertyMappings方法完成屬性映射,它是第二步的補(bǔ)充,完成resultMap標(biāo)簽中result標(biāo)簽的映射關(guān)系

最后:返回解析完成的值

到此,結(jié)果集中的一條記錄已經(jīng)被解析用戶指定的類型對象了,接下來就是要把該對象返回給用戶,這就要回到我們上一步的storeObject方法了。接下來來看下DefaultResultSetHandler#storeObject方法

storeObject

private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
  if (parentMapping != null) {
    // 處理ResultSets標(biāo)簽時(shí)走這個(gè)分支
    linkToParents(rs, parentMapping, rowValue);
  } else {
    callResultHandler(resultHandler, resultContext, rowValue);
  }
}
private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {
  resultContext.nextResultObject(rowValue);
  ((ResultHandler<Object>) resultHandler).handleResult(resultContext);
}

storeObject方法的邏輯也很簡單(一般都會走到callResultHandler方法)

第一步:通過nextResultObject方法存儲getRowValue方法解析的結(jié)果對象。

第二步:把單行記錄的解析對象存入到ResultHandler的集合當(dāng)中

嵌套映射

簡單介紹完了簡單映射之后,接下來我們來看下比較復(fù)雜的嵌套映射,在嵌套映射中也會有很多問題,比如:循環(huán)依賴如何解決、延遲加載如何解決。 本節(jié)只針對于一般情況下的嵌套映射做出分析,循環(huán)依賴和延時(shí)加載后續(xù)我會繼續(xù)更新文章。

回想一下上一小節(jié)中提到的handleRowValues方法,它會根據(jù)ResultMap對象判斷是否是嵌套映射,如果是嵌套映射,就會走入handleRowValuesForNestedResultMap方法,接下來我們就來看下handleRowValuesForNestedResultMap這個(gè)方法。

handleRowValuesForNestedResultMap

private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
  // 第一步 獲取上下文對象,用于存儲單行處理后的記錄
  final DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
  ResultSet resultSet = rsw.getResultSet();
  skipRows(resultSet, rowBounds);
  Object rowValue = previousRowValue;
  // 第二步: 遍歷結(jié)果集
  while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
    final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
    // 嵌套映射中的結(jié)果都會被存入到nestedResultObjects中。這里的CacheKey就是緩存對象唯一標(biāo)識
    final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
    // 映射過程中的對象也會被存入在此。
    Object partialObject = nestedResultObjects.get(rowKey);
    // 通常會走到該分支。獲取一行記錄處理后的對象(有可能是半成品)
    rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
    if (partialObject == null) {
      storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    }
  }
  if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) {
    storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    previousRowValue = null;
  } else if (rowValue != null) {
    previousRowValue = rowValue;
  }
}

其實(shí)仔細(xì)閱讀這段可以發(fā)現(xiàn)它和簡單映射的代碼是有一部分雷同的,這也很好理解,嵌套映射還是基于簡單映射的思想進(jìn)行遞歸處理結(jié)果集映射關(guān)系的嘛。接下來來介紹一下代碼的流程

第一步:還是獲取上下文對象,獲取JDBC的結(jié)果集對象。就不羅嗦了

第二步:遍歷結(jié)果集,處理每一行數(shù)據(jù)

第三步:創(chuàng)建CacheKey對象,使用嵌套映射中的外層對象創(chuàng)建緩存key,為了解決一對多映射

第四步:從緩存中通過CacheKey對象獲取外層對象。這里的nestedResultObjects是DefaultResultSetHandler的一個(gè)屬性,他就是用來緩存嵌套映射中的外層對象的。如果是第一次循環(huán),從緩存中獲取肯定是為空的嘛。但是你想一下這種場景——一個(gè)用戶(user)擁有多個(gè)訂單(order),這種一堆多的關(guān)系,在同一個(gè)用戶進(jìn)行到循環(huán)的第二輪時(shí),肯定不希望再創(chuàng)建一個(gè)外層對象,而是想讓order對象都公用一個(gè)外城對象。這種情況只能添加緩存來做了。這就是nestedResultObjects的意義。

這里的partialObject就是外層對象,也可以稱作是部分對象,因?yàn)樗煌暾铩?/p>

第五步:調(diào)用getRowValue方法獲取行記錄解析的結(jié)果

第六步:調(diào)用storeObject方法存儲對象到ResultHancler中

其中最重要的是要理解第四步中的嵌套思想,以及第五步解析一行記錄的詳細(xì)過程。這里一定會涉及到循環(huán)調(diào)用,因?yàn)榻馕鐾鈱訉ο蟊厝灰馕鰞?nèi)層對象嘛

getRowValue

private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, String columnPrefix, Object partialObject) throws SQLException {
  final String resultMapId = resultMap.getId();
  Object rowValue = partialObject;
  // 映射第一次肯定一定為null
  if (rowValue != null) {
    final MetaObject metaObject = configuration.newMetaObject(rowValue);
    putAncestor(rowValue, resultMapId);
    applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
    ancestorObjects.remove(resultMapId);
  } else {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
    if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      boolean foundValues = this.useConstructorMappings;
      if (shouldApplyAutomaticMappings(resultMap, true)) {
        foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
      }
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
      putAncestor(rowValue, resultMapId);
      foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
      ancestorObjects.remove(resultMapId);
      foundValues = lazyLoader.size() > 0 || foundValues;
      rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    if (combinedKey != CacheKey.NULL_CACHE_KEY) {
      nestedResultObjects.put(combinedKey, rowValue);
    }
  }
  return rowValue;
}

映射時(shí),第一次外層對象一定為null,所以會走else分支,只有在一堆多種的第二次映射才會走到if分支。我們來看下else分支的處理邏輯

第一步:首先通過createResultObject對象創(chuàng)建一個(gè)空殼對象,簡單映射中提過

第二步:通過applyAutomaticMappings方法完成自動映射

第三步:通過applyPropertyMappings方法完成屬性映射,它是第二步的補(bǔ)充,完成resultMap標(biāo)簽中result標(biāo)簽的映射關(guān)系

第四步:通過applyNestedResultMappings方法完成嵌套映射

到此,結(jié)果集中的一條記錄已經(jīng)被嵌套解析完成了。其中和簡單映射不一樣的地方只有多調(diào)用了一個(gè)applyNestedResultMappings方法,完成嵌套映射。我們來看下這個(gè)方法

applyNestedResultMappings

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) {
      // 獲取內(nèi)層對象
      rowValue = getRowValue(rsw, nestedResultMap, combinedKey, columnPrefix, rowValue);
      if (rowValue != null && !knownValue) {
        // 把內(nèi)層對象關(guān)聯(lián)到外層對象
        linkObjects(metaObject, resultMapping, rowValue);
        foundValues = true;
      }
    }
  }
  return foundValues;
}

它的執(zhí)行邏輯是遍歷resultMapping,對resultMapping進(jìn)行g(shù)etRowValue方法的調(diào)用,此時(shí)就應(yīng)該屬于簡單影射了(除非嵌套了很多層)

它通過for循環(huán)每個(gè)resultMapping,直到找到嵌套映射的哪一個(gè)字段,然后再進(jìn)行簡單映射封裝結(jié)果返回作為外層對象的屬性值。

它的調(diào)用邏輯是getRowValue——applyNestedResultMappings——getRowValue,直到嵌套映射完成位置,嵌套多少層,這個(gè)鏈路就會深多少層。

小結(jié)

mybatis解析結(jié)果集是通過遍歷結(jié)果集數(shù)據(jù),并把結(jié)果集數(shù)據(jù)對照resultMap標(biāo)簽中的映射關(guān)系一一映射,如果存在嵌套映射則嵌套執(zhí)行g(shù)etRowValue獲取一行記錄的結(jié)果并關(guān)聯(lián)到外層對象。

以上就是MyBatis handleResultSet結(jié)果集解析過程示例的詳細(xì)內(nèi)容,更多關(guān)于MyBatis handleResultSet 的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JAVA StringBuffer類與StringTokenizer類代碼解析

    JAVA StringBuffer類與StringTokenizer類代碼解析

    這篇文章主要介紹了JAVA StringBuffer類與StringTokenizer類代碼解析,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • java 字符串反轉(zhuǎn)的實(shí)例詳解

    java 字符串反轉(zhuǎn)的實(shí)例詳解

    這篇文章主要介紹了java 字符串反轉(zhuǎn)的實(shí)例詳解的相關(guān)資料,這里提供實(shí)現(xiàn)代碼幫助大家學(xué)習(xí)參考這部分內(nèi)容,需要的朋友可以參考下
    2017-08-08
  • Java中的FutureTask源碼解析

    Java中的FutureTask源碼解析

    這篇文章主要介紹了Java中的FutureTask源碼解析,FutureTask是一個(gè)可取消的異步計(jì)算,這個(gè)類是Future的實(shí)現(xiàn)類,有開始和取消一個(gè)計(jì)算的方法,如果一個(gè)計(jì)算已經(jīng)完成可以查看結(jié)果,需要的朋友可以參考下
    2023-12-12
  • Java-性能分析和監(jiān)控工具深入詳解

    Java-性能分析和監(jiān)控工具深入詳解

    這篇文章主要介紹了Java-性能分析和監(jiān)控工具深入詳解,文章內(nèi)容詳細(xì),簡單易懂,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2023-01-01
  • Java POI讀取excel中數(shù)值精度損失問題解決

    Java POI讀取excel中數(shù)值精度損失問題解決

    這篇文章主要介紹了Java POI讀取excel中數(shù)值精度損失問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • 解決springcloud阿里云OSS文件訪問跨域問題的實(shí)現(xiàn)

    解決springcloud阿里云OSS文件訪問跨域問題的實(shí)現(xiàn)

    本文主要介紹了解決springcloud阿里云OSS文件訪問跨域問題的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • SpringMVC MVC架構(gòu)原理及實(shí)現(xiàn)方法詳解

    SpringMVC MVC架構(gòu)原理及實(shí)現(xiàn)方法詳解

    這篇文章主要介紹了SpringMVC MVC架構(gòu)原理及實(shí)現(xiàn)方法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Java線程池使用AbortPolicy策略

    Java線程池使用AbortPolicy策略

    這篇文章主要介紹了?Java線程池使用AbortPolicy策略,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下
    2022-06-06
  • 使用Java實(shí)現(xiàn)將ppt轉(zhuǎn)換為文本

    使用Java實(shí)現(xiàn)將ppt轉(zhuǎn)換為文本

    這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)將ppt轉(zhuǎn)換為文本,文中的示例代碼簡潔易懂,具有一定的借鑒價(jià)值,有需要的小伙伴可以參考下
    2024-01-01
  • Spring使用AOP完成統(tǒng)一結(jié)果封裝實(shí)例demo

    Spring使用AOP完成統(tǒng)一結(jié)果封裝實(shí)例demo

    這篇文章主要介紹了Spring使用AOP完成統(tǒng)一結(jié)果封裝,本文通過實(shí)現(xiàn)demo給大家詳細(xì)講解,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-02-02

最新評論