1. 程式人生 > >MyBatis查詢的原始碼分析

MyBatis查詢的原始碼分析

如下為mybatis的一個集合查詢: 

String resource = "mybatis.cfg.xml";  
Reader reader = Resources.getResourceAsReader(resource);  
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);  
	
SqlSession sqlSession = ssf.openSession();  
	
try {  
	List<User> users = sqlSession.selectList("User.selectUser", "1");  //查詢狀態為1的使用者
	for (User user : users) {
		System.out.println(user);  
	}
} catch (Exception e) {  
	e.printStackTrace();  
} finally {  
	sqlSession.close();
}
  • 其中SqlSession預設為DefaultSqlSession:
public class DefaultSqlSession implements SqlSession {

  private Configuration configuration;
  private Executor executor;
... ...

  @Override
  public <E> List<E> selectList(String statement) {
    return this.selectList(statement, null);
  }

  @Override
  public <E> List<E> selectList(String statement, Object parameter) {
    return this.selectList(statement, parameter, RowBounds.DEFAULT);	//其中RowBounds.DEFAULT為new RowBounds();
  }

  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
	//MappedStatement是mybatis根據<select id="selectByExample" resultMap="ResultMap" ... />建立的對映物件
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

... ...
}
/**
  * 行數限制
  */
public class RowBounds {

  public static final int NO_ROW_OFFSET = 0;
  public static final int NO_ROW_LIMIT = Integer.MAX_VALUE;
  public static final RowBounds DEFAULT = new RowBounds();

  private int offset;
  private int limit;

  public RowBounds() {
    this.offset = NO_ROW_OFFSET;
    this.limit = NO_ROW_LIMIT;
  }

  public RowBounds(int offset, int limit) {
    this.offset = offset;
    this.limit = limit;
  }
... ...
}
  • 當我們啟用快取後查詢執行器Executor為CachingExector:
public class CachingExecutor implements Executor {

  private Executor delegate;
  private TransactionalCacheManager tcm = new TransactionalCacheManager();

  public CachingExecutor(Executor delegate) {
    this.delegate = delegate;//這裡的delegate為abstract class BaseExecutor implements Executor
    delegate.setExecutorWrapper(this);
  }
... ...

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    Cache cache = ms.getCache();
    if (cache != null) {
      flushCacheIfRequired(ms);//如果<select id="selectByExample" resultMap="ResultMap" flushCache="true" ... />中設定flushCache="true",則清除快取
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, parameterObject, boundSql);//確保查詢不包括輸出引數,因為快取程式不支援輸出引數
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);//從快取管理器中獲取快取(快取管理器是對各區塊快取的統一管理工具)
        if (list == null) {	//如果從快取中獲取不到,則執行查詢
          list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); //將查詢到的結果放入快取
        }
        return list;
      }
    }
    return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

... ...

}
  • CachingExecutor中的執行器代理delegate一般為ReuseExecutor:
public class ReuseExecutor extends BaseExecutor {

... ...

  @Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Configuration configuration = ms.getConfiguration();
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
    Statement stmt = prepareStatement(handler, ms.getStatementLog());
    return handler.<E>query(stmt, resultHandler); //執行查詢
  }

... ...

}
  • StatementHandler一般為路由StatementHandler,即RoutingStatementHandler:
public class RoutingStatementHandler implements StatementHandler {

  private final StatementHandler delegate;

  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
/*這裡的switch-case即是傳說中的策略模式*/
    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }

  }
  • RoutingStatementHandler其中的StatementHandler代理delegate,通常為PreparedStatementHandler;其中的query(...)方法通過呼叫ResultHandler的handleResultSets(...)封裝查詢結果:
public class PreparedStatementHandler extends BaseStatementHandler {

... ...
  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();	//執行查詢
    return resultSetHandler.<E> handleResultSets(ps);	//處理結果集
  }
... ...
}
  • ResultSetHandler只有一個預設結果集處理器DefaultResultSetHandler:
public interface ResultSetHandler {
  /**
    * 處理結果集
    */
  <E> List<E> handleResultSets(Statement stmt) throws SQLException;

... ...

}
public class DefaultResultSetHandler implements ResultSetHandler {
  ... ...
  // nested resultmaps
  private final Map<CacheKey, Object> nestedResultObjects = new HashMap<CacheKey, Object>();//巢狀結果快取
  private final Map<CacheKey, Object> ancestorObjects = new HashMap<CacheKey, Object>();//祖物件快取,即最外層的物件快取
  private final Map<String, String> ancestorColumnPrefix = new HashMap<String, String>();
  ... ...
  
  /**
    * 處理所有的結果集(一次查詢可能有多個語句,所以可能有多個結果集)
    */
  @Override
  public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

    final List<Object> multipleResults = new ArrayList<Object>();

    int resultSetCount = 0;
    ResultSetWrapper rsw = getFirstResultSet(stmt);//獲取java.sql.ResultSet的第一個結果集(此時sql已被執行)

    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
    while (rsw != null && resultMapCount > resultSetCount) {	//遍歷所有的結果集(一般僅一個結果集,因為通常僅一條查詢語句)
      ResultMap resultMap = resultMaps.get(resultSetCount);
      handleResultSet(rsw, resultMap, multipleResults, null);	//根據ResultSetWrapper和ResultMap處理結果集
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }

/*---------該方法中的以下程式碼暫且不做分析------------*/
    String[] resultSets = mappedStatement.getResulSets();
    if (resultSets != null) {
      while (rsw != null && resultSetCount < resultSets.length) {
        ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
        if (parentMapping != null) {
          String nestedResultMapId = parentMapping.getNestedResultMapId();
          ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
          handleResultSet(rsw, resultMap, null, parentMapping);
        }
        rsw = getNextResultSet(stmt);
        cleanUpAfterHandlingResultSet();
        resultSetCount++;
      }
    }

    return collapseSingleResultList(multipleResults);
  }

... ...

  private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
      if (parentMapping != null) {
        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
      } else {
        if (resultHandler == null) {//使用結果處理器為空,則生成一個預設結果處理器
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
          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());
    }
  }

... ...

  /**
* 處理所有行記錄中的值
*/
  private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    if (resultMap.hasNestedResultMaps()) {
      ensureNoRowBounds();
      checkResultHandler();
      handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);//巢狀對映
    } else {
      handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);//簡單對映
    }
  }

... ...

  /**
    * 處理行值集到簡單結果的對映
    */
  private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
      throws SQLException {
    DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
    skipRows(rsw.getResultSet(), rowBounds);
    while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
      Object rowValue = getRowValue(rsw, discriminatedResultMap);
      storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
    }
  }

... ...

   /**
    * 處理行值集到巢狀結果的對映
    */
   private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    final DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
    skipRows(rsw.getResultSet(), rowBounds);
    Object rowValue = null;
    while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
      final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
      final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
      Object partialObject = nestedResultObjects.get(rowKey);//嘗試從nestedResultObjects(是HashMap<CacheKey, Object>)中獲取原物件
      if (mappedStatement.isResultOrdered()) {
        if (partialObject == null && rowValue != null) {
          nestedResultObjects.clear();
          storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
        }
        rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, rowKey, null, partialObject);//獲取行值
      } else {
        rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, rowKey, null, partialObject);//獲取行值
        if (partialObject == null) {
          storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
        }
      }
    }
    if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) {
      storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
    }
  }

... ...


  /**
    * 建立快取的KEY(具體key的生成策略可詳見文末)
    */
  private CacheKey createRowKey(ResultMap resultMap, ResultSetWrapper rsw, String columnPrefix) throws SQLException {
    final CacheKey cacheKey = new CacheKey();
    cacheKey.update(resultMap.getId());
    List<ResultMapping> resultMappings = getResultMappingsForRowKey(resultMap);
    if (resultMappings.size() == 0) {
      if (Map.class.isAssignableFrom(resultMap.getType())) {
        createRowKeyForMap(rsw, cacheKey);
      } else {
        createRowKeyForUnmappedProperties(resultMap, rsw, cacheKey, columnPrefix);
      }
    } else {
      createRowKeyForMappedProperties(resultMap, rsw, cacheKey, resultMappings, columnPrefix);
    }
    return cacheKey;
  }

... ...

  /**
    * 從查詢的一條行記錄中獲取需要對映為結果屬性的值
    */
  private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, CacheKey absoluteKey, String columnPrefix, Object partialObject) throws SQLException {
    final String resultMapId = resultMap.getId();
    Object resultObject = partialObject;
/*如果傳過來的原物件不為空,則向其中設定屬性值;
否則,建立一個新結果物件作為原物件,然後設定屬性值*/
    if (resultObject != null) {
      final MetaObject metaObject = configuration.newMetaObject(resultObject);
      putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
      applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);	//應用巢狀對映
      ancestorObjects.remove(absoluteKey);
    } else {
      final ResultLoaderMap lazyLoader = new ResultLoaderMap();
      resultObject = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
      if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
        final MetaObject metaObject = configuration.newMetaObject(resultObject);
        boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
        if (shouldApplyAutomaticMappings(resultMap, true)) {
          foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
        }
	   //屬性對映
        foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
        putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
	   //巢狀對映
        foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
        ancestorObjects.remove(absoluteKey);
        foundValues = lazyLoader.size() > 0 || foundValues;
        resultObject = foundValues ? resultObject : null;
      }
      if (combinedKey != CacheKey.NULL_CACHE_KEY) {
        nestedResultObjects.put(combinedKey, resultObject);
      }
    }
    return resultObject;
  }

... ...

  /**
    * 應用屬性對映
    */
  private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
      throws SQLException {
    final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
    boolean foundValues = false;
    final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
    for (ResultMapping propertyMapping : propertyMappings) {
      String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      if (propertyMapping.getNestedResultMapId() != null) {
        // the user added a column attribute to a nested result map, ignore it
        column = null;
      }
      if (propertyMapping.isCompositeResult()
          || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
          || propertyMapping.getResultSet() != null) {
        Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
        final String property = propertyMapping.getProperty();
        if (value != DEFERED
            && property != null
            && (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive()))) {
          metaObject.setValue(property, value);
        }
        if (value != null || value == DEFERED) {
          foundValues = true;
        }
      }
    }
    return foundValues;
  }

... ...

   /**
    * 應用巢狀結果對映
    */
   private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String parentPrefix, CacheKey parentRowKey, boolean newObject) {
    boolean foundValues = false;
//迴圈結果對映中所有的屬性對映,如果屬性為物件,即巢狀結果對映,則遞迴呼叫getRowValue(...)方法
    for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) {
      final String nestedResultMapId = resultMapping.getNestedResultMapId();
      if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
        try {
          final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);
          final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix);
          CacheKey rowKey = null;
          Object ancestorObject = null;
          if (ancestorColumnPrefix.containsKey(nestedResultMapId)) {
            rowKey = createRowKey(nestedResultMap, rsw, ancestorColumnPrefix.get(nestedResultMapId));
            ancestorObject = ancestorObjects.get(rowKey);
          }
          if (ancestorObject != null) {
            if (newObject) {
              linkObjects(metaObject, resultMapping, ancestorObject); // issue #385
            }
          } else {
            rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
            final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
            Object rowValue = nestedResultObjects.get(combinedKey);
            boolean knownValue = (rowValue != null);
            instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject); // mandatory            
            if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw.getResultSet())) {
		   //遞迴呼叫getRowValue(...)方法
              rowValue = getRowValue(rsw, nestedResultMap, combinedKey, rowKey, columnPrefix, rowValue);
              if (rowValue != null && !knownValue) {
                linkObjects(metaObject, resultMapping, rowValue);
                foundValues = true;
              }
            }
          }
        } catch (SQLException e) {
          throw new ExecutorException("Error getting nested result map values for '" + resultMapping.getProperty() + "'.  Cause: " + e, e);
        }
      }
    }
    return foundValues;
  }
}
/**
  * 結果對映
  */
public class ResultMap {
  private String id;		//結果對映ID
  private Class<?> type;	//對映結果型別
  private List<ResultMapping> resultMappings;	//所有內嵌的結果對映
  private List<ResultMapping> idResultMappings;	//所有內嵌的ID結果對映
  private List<ResultMapping> constructorResultMappings;	//所有構造對映
  private List<ResultMapping> propertyResultMappings;		//所有的屬性對映
... ...

  private ResultMap() {
  }
... ...
}
  • 備註:DefaultResultSetHandler中CacheKey的建立策略
<resultMap id="BaseResultMap" type="com.muwu.mjh.product.model.Cupboard" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="name" property="name" jdbcType="VARCHAR" />
    <result column="mark" property="mark" jdbcType="VARCHAR" />
<association property="unit" javaType="com.muwu.mjh.system.model.Unit" autoMapping="false">
    	<id property="id" column="unit_id"/>
    	<result property="name" column="unit_name"/>
    </association>
	<association property="productType" javaType="com.muwu.mjh.product.model.ProductType" autoMapping="false">
    	<id property="id" column="product_type_id"/>
    	<result property="name" column="product_type_name"/>
    	<result property="parentId" column="parent_id"/>
    </association>
    <collection property="modules" ofType="com.muwu.mjh.product.model.cupboard.Module" autoMapping="false" >
    	<id property="id" column="module_id"/>
    	<id property="sort" column="module_sort"/>
    	<result property="name" column="module_name"/>
    	<result property="mark" column="module_mark"/>
    	<collection property="components" ofType="com.muwu.mjh.product.model.cupboard.Component" autoMapping="false">
    		<id property="id" column="component_id"/>
    		<result property="name" column="component_name"/>
    		<result property="mark" column="component_mark"/>
    		<result property="image" column="component_image"/>
    		<result property="picture" column="component_picture"/>
    	</collection>
    </collection>
</resultMap>

對映時生成的快取key依次形如:

13544163:-1571759273:com.muwu.mjh.product.mapper.CupboardMapper.

    RichResultMap:id:16942

-2046111186:1023173599:com.muwu.mjh.product.mapper.CupboardMapper.

    mapper_resultMap[RichResultMap]_association[unit]:unit_id:10

2024729156:2397089841:com.muwu.mjh.product.mapper.CupboardMapper.

    mapper_resultMap[RichResultMap]_association[productType]:product_type_id:19

1199939766:-5622484385:com.muwu.mjh.product.mapper.CupboardMapper.

    mapper_resultMap[RichResultMap]_collection[modules]:module_id:51:module_sort:0

559266669:-1005085733:com.muwu.mjh.product.mapper.CupboardMapper.

    mapper_resultMap[RichResultMap]_collection[modules]_collection[components]:component_id:200

可見被<id property="..." column="..."/>標註的屬性和欄位值都會作為CacheKey的一部分