1. 程式人生 > 其它 >mybatis原始碼解讀:executor包(結果處理功能)

mybatis原始碼解讀:executor包(結果處理功能)

技術標籤:mybaits原始碼mybatis

歡迎關注本人公眾號:

mybatis查詢結果的處理需要完成的步驟有:

1.處理結果對映中的巢狀對映等邏輯

2.根據對映關係,生成結果物件

3.根據資料庫查詢記錄對結果物件的屬性進行賦值

4.將結果物件彙總為List,Map,Cursor等形式。


1.結果處理功能

其中executor包中的result子包將負責完成"將結果物件彙總為List,Map,Cursor等形式"的簡單功能的一部分。

result子包中主要有3個類:DefaultResultContext類、DefaultResultHandler類、DefaultMapResultHandler類。

DefaultResultContext類用來儲存一個結果物件,對應資料庫的一條記錄。

public class DefaultResultContext<T> implements ResultContext<T> {  // 結果物件  private T resultObject;  // 結果計數(表明這是第幾個結果物件)  private int resultCount;  // 使用完畢(結果已經被取走)privatebooleanstopped;}

DefaultResultHandler類負責將DefaultResultContext類中的結果物件聚合成一個List返回。

public class DefaultResultHandler implements ResultHandler<Object> {  private final List<Object> list;  public DefaultResultHandler() {    list = new ArrayList<>();  }  @SuppressWarnings("unchecked")  public DefaultResultHandler(ObjectFactory objectFactory) {    list = objectFactory.create(List.class);
} @Override public void handleResult(ResultContext<?> context) { list.add(context.getResultObject()); } public List<Object> getResultList() { return list; }}

DefualtMapResultHandler類負責將DefaultResultContext類中的結果物件聚合成一個Map返回。

public class DefaultMapResultHandler<K, V> implements ResultHandler<V> {  // Map形式的對映結果  private final Map<K, V> mappedResults;  // Map的鍵。由使用者指定,是結果物件中的某個屬性名  private final String mapKey;  // 物件工廠  private final ObjectFactory objectFactory;  // 物件包裝工廠  private final ObjectWrapperFactory objectWrapperFactory;  // 反射工廠  private final ReflectorFactory reflectorFactory;  /**   * 處理一個結果   * @param context 一個結果   */  @Override  public void handleResult(ResultContext<? extends V> context) {    // 從結果上下文中取出結果物件    final V value = context.getResultObject();    // 獲得結果物件的元物件    final MetaObject mo = MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);    // 基於元物件取出key對應的值    final K key = (K) mo.getValue(mapKey);    mappedResults.put(key, value);  }  public Map<K, V> getMappedResults() {    return mappedResults;  }}

2.結果集處理功能

其中executor包中的resultset子包負責的功能有:

1.處理結果對映中的巢狀對映等邏輯

2.根據對映關係,生成結果物件

3.根據資料庫查詢記錄對結果物件的屬性進行賦值

resultset子包主要有ResultSetWrapper結果封裝類,ResultSetHandler和DefaultResultSetHandler分別是結果集處理器的介面和實現類。

ResultSetWrapper類是對java.sql.ResultSet介面的進一步封裝,在此基礎上擴展出更多的功能,用到了裝飾器模式。

public class ResultSetWrapper {  // 被裝飾的resultSet物件  private final ResultSet resultSet;  // 型別處理器登錄檔  private final TypeHandlerRegistry typeHandlerRegistry;  // resultSet中各個列對應的列名列表  private final List<String> columnNames = new ArrayList<>();  // resultSet中各個列對應的Java型別名列表  private final List<String> classNames = new ArrayList<>();  // resultSet中各個列對應的JDBC型別列表  private final List<JdbcType> jdbcTypes = new ArrayList<>();  // <列名,< java型別,TypeHandler>>  // 這裡的資料是不斷組建起來的。java型別傳入,然後去全域性handlerMap索引java型別的handler放入map,然後在賦給列名。  // 每個列後面的java型別不應該是唯一的麼?不是的  //    <resultMap id="userMapFull" type="com.example.demo.UserBean">  //        <result property="id" column="id"/>  //        <result property="schoolName" column="id"/>  //    </resultMap>  // 上面就可能不唯一,同一個列可以給不同的java屬性  // 型別與型別處理器的對映表。結構為:Map<列名,Map<Java型別,型別處理器>>  private final Map<String, Map<Class<?>, TypeHandler<?>>> typeHandlerMap = new HashMap<>();  // 記錄了所有的有對映關係的列。  // key為resultMap的id,後面的List為該resultMap中有對映的列的列表  // <resultMap的id,List<物件對映的列名>>  // 記錄了所有的有對映關係的列。結構為:Map<resultMap的id,List<物件對映的列名>>  private final Map<String, List<String>> mappedColumnNamesMap = new HashMap<>();  // 記錄了所有的無對映關係的列。  // key為resultMap的id,後面的List為該resultMap中無對映的列的列表  //  // <resultMap的id : List<物件對映的列名>>  // 記錄了所有的無對映關係的列。結構為:Map<resultMap的id,List<物件對映的列名>>privatefinalMap<String,List<String>>unMappedColumnNamesMap=newHashMap<>();/**   * 如果通過列名、屬性型別找到之前存好的handler,則就是它   * 如果通過列名沒找到:   *  1、通過列名找到其jdbc型別   *  2、根據java型別、jdbc型別,找到對應的handler   *   * @param propertyType   * @param columnName   * @return   */  public TypeHandler<?> getTypeHandler(Class<?> propertyType, String columnName) {    TypeHandler<?> handler = null;    Map<Class<?>, TypeHandler<?>> columnHandlers = typeHandlerMap.get(columnName);    if (columnHandlers == null) {      columnHandlers = new HashMap<>();      typeHandlerMap.put(columnName, columnHandlers);    } else {      handler = columnHandlers.get(propertyType);    }    // 如果之前沒有,則找到後放入備用    if (handler == null) {      JdbcType jdbcType = getJdbcType(columnName);      // 根據型別去全域性尋找對應的handlerhandler=typeHandlerRegistry.getTypeHandler(propertyType,jdbcType);      if (handler == null || handler instanceof UnknownTypeHandler) {        final int index = columnNames.indexOf(columnName);        final Class<?> javaType = resolveClass(classNames.get(index));        if (javaType != null && jdbcType != null) {          handler = typeHandlerRegistry.getTypeHandler(javaType, jdbcType);        } else if (javaType != null) {          handler = typeHandlerRegistry.getTypeHandler(javaType);        } else if (jdbcType != null) {          handler = typeHandlerRegistry.getTypeHandler(jdbcType);        }      }      if (handler == null || handler instanceof UnknownTypeHandler) {        handler = new ObjectTypeHandler();      }      columnHandlers.put(propertyType, handler);    }    return handler;  }  }

ResultSetHandler是結果集處理器介面

public interface ResultSetHandler {  // 將Statement的執行結果處理為List  <E> List<E> handleResultSets(Statement stmt) throws SQLException;  // 將Statement的執行結果處理為Map  <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;  // 處理儲存過程的輸出結果  void handleOutputParameters(CallableStatement cs) throws SQLException;}

DefaultResultSetHandler類作為ResultSetHandler介面的預設也是唯一的實現類

 /**   * 處理Statement得到的多結果集(也可能是單結果集,這是多結果集的一種簡化形式),最終得到結果列表   * @param stmt Statement語句   * @return 結果列表   * @throws SQLException   */  @Override  public List<Object> handleResultSets(Statement stmt) throws SQLException {    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());    // 用以儲存處理結果的列表    final List<Object> multipleResults = new ArrayList<>();    // 可能會有多個結果集,該變數用來對結果集進行計數    int resultSetCount = 0;    // 可能會有多個結果集,先取出第一個結果集    ResultSetWrapper rsw = getFirstResultSet(stmt);    // 查詢語句對應的resultMap節點,可能含有多個    List<ResultMap> resultMaps = mappedStatement.getResultMaps();    int resultMapCount = resultMaps.size();    // 合法性校驗(存在輸出結果集的情況下,resultMapCount不能為0)    validateResultMapsCount(rsw, resultMapCount);    // 迴圈遍歷每一個設定了resultMap的結果集    while (rsw != null && resultMapCount > resultSetCount) {      // 獲得當前結果集對應的resultMap      ResultMap resultMap = resultMaps.get(resultSetCount);      // 進行結果集的處理      handleResultSet(rsw, resultMap, multipleResults, null);      // 獲取下一結果集      rsw = getNextResultSet(stmt);      // 清理上一條結果集的環境      cleanUpAfterHandlingResultSet();      resultSetCount++;    }    // 獲取多結果集中所有結果集的名稱    String[] resultSets = mappedStatement.getResultSets();    if (resultSets != null) {      // 迴圈遍歷每一個沒有設定resultMap的結果集      while (rsw != null && resultSetCount < resultSets.length) {        // 獲取該結果集對應的父級resultMap中的resultMapping(注:resultMapping用來描述物件屬性的對映關係)        ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);        if (parentMapping != null) {          // 獲取被巢狀的resultMap的編號          String nestedResultMapId = parentMapping.getNestedResultMapId();          ResultMap resultMap = configuration.getResultMap(nestedResultMapId);          // 處理巢狀對映          handleResultSet(rsw, resultMap, null, parentMapping);        }        rsw = getNextResultSet(stmt);        cleanUpAfterHandlingResultSet();        resultSetCount++;      }    }    // 判斷是否是單結果集:如果是則返回結果列表;如果否則返回結果集列表    return collapseSingleResultList(multipleResults);  }    /**   * 處理單一的結果集   * @param rsw ResultSet的包裝   * @param resultMap resultMap節點的資訊   * @param multipleResults 用來儲存處理結果的list   * @param parentMapping   * @throws SQLException   */  private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {    try {      if (parentMapping != null) { // 巢狀的結果        // 向子方法傳入parentMapping。處理結果中的記錄。        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);      } else { // 非巢狀的結果        if (resultHandler == null) {          // defaultResultHandler能夠將結果物件聚合成一個List返回          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);          // 處理結果中的記錄。          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);          multipleResults.add(defaultResultHandler.getResultList());        } else {          handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);        }      }    } finally {      closeResultSet(rsw.getResultSet());    }  }     /**   * 處理單結果集中的屬性   * @param rsw 單結果集的包裝   * @param resultMap 結果對映   * @param resultHandler 結果處理器   * @param rowBounds 翻頁限制條件   * @param parentMapping 父級結果對映   * @throws SQLException   */  public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler,                              RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {    if (resultMap.hasNestedResultMaps()) {      // 前置校驗      ensureNoRowBounds();      checkResultHandler();      // 處理巢狀對映      handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);    } else {      // 處理單層對映      handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);    }  }     /**   * 處理非巢狀對映的結果集   * @param rsw 結果集包裝   * @param resultMap 結果對映   * @param resultHandler 結果處理器   * @param rowBounds 翻頁限制條件   * @param parentMapping 父級結果對映   * @throws SQLException   */  private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)      throws SQLException {    DefaultResultContext<Object> resultContext = new DefaultResultContext<>();    // 當前要處理的結果集    ResultSet resultSet = rsw.getResultSet();    // 根據翻頁配置,跳過指定的行    skipRows(resultSet, rowBounds);    // 持續處理下一條結果,判斷條件為:還有結果需要處理 && 結果集沒有關閉 && 還有下一條結果    while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {      // 經過鑑別器鑑別,確定經過鑑別器分析的最終要使用的resultMap      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);      // 拿到了一行記錄,並且將其轉化為一個物件      Object rowValue = getRowValue(rsw, discriminatedResultMap, null);      // 把這一行記錄轉化出的物件存起來      storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);    }  }    /**   * 儲存當前結果物件   * @param resultHandler 結果處理器   * @param resultContext 結果上下文   * @param rowValue 結果物件   * @param parentMapping 父級結果對映   * @param rs 結果集   * @throws SQLException   */  private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {    if (parentMapping != null) {      // 存在父級,則將這一行記錄對應的結果物件繫結到父級結果上      linkToParents(rs, parentMapping, rowValue);    } else {      // 使用resultHandler聚合該物件      callResultHandler(resultHandler, resultContext, rowValue);    }  }

可見在HandleResultSets方法中完成了生成結果物件,為結果物件屬性賦值,將結果物件進行聚合或繫結等重要操作。