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的一部分