Mybatis3.5.1源碼分析
- Mybatis-SqlSessionFactoryBuilder邢隧,XMLConfigBuilder扑庞,XPathParser源碼解析
- Mybatis-Configuration源碼解析
- Mybatis-事務(wù)對象源碼解析
- Mybatis-數(shù)據(jù)源源碼解析
- Mybatis緩存策略源碼解析
- Mybatis-DatabaseIdProvider源碼解析
- Mybatis-TypeHandler源碼解析
- Mybatis-Reflector源碼解析
- Mybatis-ObjectFactory,ObjectWrapperFactory源碼分析
- Mybatis-Mapper各類標(biāo)簽封裝類源碼解析
- Mybatis-XMLMapperBuilder,XMLStatmentBuilder源碼分析
- Mybatis-MapperAnnotationBuilder源碼分析
- [Mybatis-MetaObject,MetaClass源碼解析]http://www.reibang.com/p/f51fa552f30a)
- Mybatis-LanguageDriver源碼解析
- Mybatis-SqlSource源碼解析
- Mybatis-SqlNode源碼解析
- Mybatis-KeyGenerator源碼解析
- Mybatis-Executor源碼解析
- Mybatis-ParameterHandler源碼解析
- Mybatis-StatementHandler源碼解析
- Mybatis-DefaultResultSetHandler(一)源碼解析
- Mybatis-DefaultResultSetHandler(二)源碼解析
- Mybatis-ResultHandler,Cursor,RowBounds 源碼分析
- Mybatis-MapperProxy源碼解析
- Mybatis-SqlSession源碼解析
- Mybatis-Interceptor源碼解析
DefaultResultSetHandler
package org.apache.ibatis.executor.resultset;
/**
* 默認(rèn)的結(jié)果集處理器
* <p>
* 別名說明:
* <ol>
* <li>Mapper.xml的resultMap標(biāo)簽信息封裝類對象 簡稱 resultMap標(biāo)簽對象</li>
* <li>根據(jù)resultMap對象與結(jié)果集構(gòu)建出來的java類型對象,簡稱為 結(jié)果對象</li>
* </ol>
*
* </p>
* <p>參考博客:<a >https://my.oschina.net/u/3768341/blog/3040013</a></p>
* <p>https://my.oschina.net/heweipo/blog/621613</p>
* @author Clinton Begin
* @author Eduardo Macarron
* @author Iwao AVE!
* @author Kazuki Shimizu
*/
public class DefaultResultSetHandler implements ResultSetHandler {
/**
* 標(biāo)記著待定的對象
*/
private static final Object DEFERRED = new Object();
/**
* 執(zhí)行器
*/
private final Executor executor;
/**
* mybatis全局配置信息
*/
private final Configuration configuration;
/**
* Mapper.xml文件的select,delete,update,insert這些DML標(biāo)簽的封裝類
*/
private final MappedStatement mappedStatement;
/**
* Mybatis的分頁對象
*/
private final RowBounds rowBounds;
/**
* 參數(shù)處理器
*/
private final ParameterHandler parameterHandler;
/**
* 結(jié)果處理器
*/
private final ResultHandler<?> resultHandler;
/**
* 參數(shù)映射與可執(zhí)行SQL封裝類對象
*/
private final BoundSql boundSql;
/**
* 類型處理器注冊器對象
*/
private final TypeHandlerRegistry typeHandlerRegistry;
/**
* 對象工廠,從mybatis全局配置信息中獲取
*/
private final ObjectFactory objectFactory;
/**
* 反射工廠,從mybatis全局配置信息中獲取
*/
private final ReflectorFactory reflectorFactory;
// nested resultmaps
/**
* key=緩存Key,value=嵌套的結(jié)果對象
*/
private final Map<CacheKey, Object> nestedResultObjects = new HashMap<>();
private final Map<String, Object> ancestorObjects = new HashMap<>();
/**
* 上一次嵌套的resultMap對象所構(gòu)建出來的對象
*/
private Object previousRowValue;
// multiple resultsets
private final Map<String, ResultMapping> nextResultMaps = new HashMap<>();
/**
* PendingRelation是DefaultResultSetHandler的內(nèi)部靜態(tài)類骂铁,記錄了當(dāng)前結(jié)果對象對應(yīng)的MetaObject對象以及parentMapping對象
* 該對象就為CacheKey對象跟全部的PendingRelation對象的映射
*/
private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<>();
// Cached Automappings
/**
* 自動映射關(guān)系緩存Map
*/
private final Map<String, List<UnMappedColumnAutoMapping>> autoMappingsCache = new HashMap<>();
// temporary marking flag that indicate using constructor mapping (use field to reduce memory usage)
// 表明使用構(gòu)造函數(shù)映射關(guān)系的臨時標(biāo)志標(biāo)記(使用成員變量來減少內(nèi)存開銷)
/**
* 當(dāng)前結(jié)果對象是否使用了非無參構(gòu)造函數(shù)進(jìn)行構(gòu)建的標(biāo)記
*/
private boolean useConstructorMappings;
/**
* 待定關(guān)系
*/
private static class PendingRelation {
/**
* 元對象
*/
public MetaObject metaObject;
/**
* 結(jié)果映射
*/
public ResultMapping propertyMapping;
}
private static class UnMappedColumnAutoMapping {
/**
* 字段名
*/
private final String column;
/**
* 屬性名
*/
private final String property;
/**
* TypeHandler 處理器
*/
private final TypeHandler<?> typeHandler;
/**
* 是否為基本屬性
*/
private final boolean primitive;
/**
*
* @param column 字段名
* @param property 屬性名
* @param typeHandler TypeHandler 處理器
* @param primitive 是否為基本屬性
*/
public UnMappedColumnAutoMapping(String column, String property, TypeHandler<?> typeHandler, boolean primitive) {
this.column = column;
this.property = property;
this.typeHandler = typeHandler;
this.primitive = primitive;
}
}
/**
*
* @param executor 執(zhí)行器
* @param mappedStatement Mapper.xml文件的select,delete,update,insert這些DML標(biāo)簽的封裝類
* @param parameterHandler 參數(shù)處理器
* @param resultHandler 結(jié)果處理器
* @param boundSql 參數(shù)映射與可執(zhí)行SQL封裝類對象
* @param rowBounds Mybatis的分頁對象
*/
public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler, ResultHandler<?> resultHandler, BoundSql boundSql,
RowBounds rowBounds) {
this.executor = executor;
this.configuration = mappedStatement.getConfiguration();
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;
this.parameterHandler = parameterHandler;
this.boundSql = boundSql;
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();
this.reflectorFactory = configuration.getReflectorFactory();
this.resultHandler = resultHandler;
}
//
// HANDLE OUTPUT PARAMETER
//
@Override
public void handleOutputParameters(CallableStatement cs) throws SQLException {
//獲取參數(shù)對象
final Object parameterObject = parameterHandler.getParameterObject();
//構(gòu)建參數(shù)元對象
final MetaObject metaParam = configuration.newMetaObject(parameterObject);
//獲取參數(shù)映射集合
final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
//遍歷參數(shù)映射集合
for (int i = 0; i < parameterMappings.size(); i++) {
//獲取參數(shù)映射
final ParameterMapping parameterMapping = parameterMappings.get(i);
//如果參數(shù)映射的模式為輸出參數(shù) 或者 參數(shù)映射的模式為輸入/輸出參數(shù)
if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
//如果參數(shù)映射配置java類型是ResultSet
if (ResultSet.class.equals(parameterMapping.getJavaType())) {
//處理結(jié)果游標(biāo)的輸出參數(shù),將結(jié)果對象集合賦值到參數(shù)對象對應(yīng)的屬性中
handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam);
} else {
//獲取類型處理器
final TypeHandler<?> typeHandler = parameterMapping.getTypeHandler();
//通過typeHandler獲取指定列位置的結(jié)果對象罩抗,然后賦值到參數(shù)對象對應(yīng)的屬性中
metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1));
}
}
}
}
/**
* 處理結(jié)果游標(biāo)的輸出參數(shù)拉庵,將結(jié)果對象集合賦值到參數(shù)對象對應(yīng)的屬性中
* @param rs 結(jié)果集
* @param parameterMapping 對應(yīng)于paramterMap的paramter標(biāo)簽參數(shù)映射封裝類對象
* @param metaParam 參數(shù)元對象
*/
private void handleRefCursorOutputParameter(ResultSet rs, ParameterMapping parameterMapping, MetaObject metaParam) throws SQLException {
//如果結(jié)果集為null
if (rs == null) {
return;
}
try {
//獲取參數(shù)映射配置的resultMap標(biāo)簽Id
final String resultMapId = parameterMapping.getResultMapId();
//獲取resultMapId對應(yīng)的ResultMap對象
final ResultMap resultMap = configuration.getResultMap(resultMapId);
//將rs進(jìn)行包裝
final ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration);
//如果結(jié)果處理器為null
if (this.resultHandler == null) {
//默認(rèn)ResultHandler,通過ObjectFactory去構(gòu)建list來接收結(jié)果
//構(gòu)建一個默認(rèn)結(jié)果處理器套蒂,里面就是通過objectFactory構(gòu)建list對象,本質(zhì)是一個list.
final DefaultResultHandler resultHandler = new DefaultResultHandler(objectFactory);
//處理結(jié)果集
handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
//將結(jié)果對象集合賦值到參數(shù)對象對應(yīng)的屬性中
metaParam.setValue(parameterMapping.getProperty(), resultHandler.getResultList());
} else {
//處理結(jié)果集
handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
}
} finally {
// issue #228 (close resultsets) 關(guān)閉結(jié)果集,捕捉SQLException并不作任何處理
closeResultSet(rs);
}
}
//
// HANDLE RESULT SETS
//
/**
* 處理 {@code stmt} 中的所有結(jié)果集钞支,返回結(jié)果對象集合
* @param stmt SQL容器
*/
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
//設(shè)置日志的上下文
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
//初始化一個集合對象,用于保存多個結(jié)果對象
final List<Object> multipleResults = new ArrayList<>();
//初始化結(jié)果集數(shù)量為0
int resultSetCount = 0;
//獲取第一個結(jié)果集對象
ResultSetWrapper rsw = getFirstResultSet(stmt);
//獲取ResultMap標(biāo)簽對象集合
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
//獲取集合元素數(shù)量
int resultMapCount = resultMaps.size();
//驗證ResultMap標(biāo)簽對象數(shù)量,如果rsw不為null且ResultMapCount小于1操刀,就會拋出異常
validateResultMapsCount(rsw, resultMapCount);
//如果結(jié)果集包裝類對象不為null 且 配置的ResultMap標(biāo)簽對象數(shù)量大于結(jié)果集數(shù)量
while (rsw != null && resultMapCount > resultSetCount) {
//從集合中獲取ResultMap標(biāo)簽對象
ResultMap resultMap = resultMaps.get(resultSetCount);
/**
* 構(gòu)建出來的結(jié)果對象,如果父級結(jié)果屬性映射不為null烁挟,會將結(jié)果對象賦值到父級結(jié)果屬性對應(yīng)的結(jié)果對象中,
* 否則將結(jié)果對象加入到reusltHandler中馍刮。最后從reusltHandler中取的最終的結(jié)果對象加入到多個結(jié)果
* 對象集合中
*/
handleResultSet(rsw, resultMap, multipleResults, null);
//獲取下一個結(jié)果集對象
rsw = getNextResultSet(stmt);
//清空所有的嵌套結(jié)果對象
cleanUpAfterHandlingResultSet();
//每處理完一次信夫,結(jié)果集數(shù)量+1
resultSetCount++;
}
//獲取配置的結(jié)果集名
String[] resultSets = mappedStatement.getResultSets();
//如果結(jié)果集不為null
if (resultSets != null) {
//如果結(jié)果包裝對象不為null 而且 結(jié)果集數(shù)量小于配置的結(jié)果集名數(shù)量
while (rsw != null && resultSetCount < resultSets.length) {
//獲取父級結(jié)果屬性映射對象
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
//如果父級結(jié)果屬性映射對象不為null
if (parentMapping != null) {
//獲取嵌套的resultMap標(biāo)簽對象Id
String nestedResultMapId = parentMapping.getNestedResultMapId();
//獲取nestedResultMapId對應(yīng)的ResultMap標(biāo)簽對象
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
/**
* 構(gòu)建出來的結(jié)果對象,如果父級結(jié)果屬性映射不為null窃蹋,會將結(jié)果對象賦值到父級結(jié)果屬性對應(yīng)的結(jié)果對象中卡啰,
* 否則將結(jié)果對象加入到reusltHandler中。最后從reusltHandler中取的最終的結(jié)果對象加入到多個結(jié)果
* 對象集合中
*/
handleResultSet(rsw, resultMap, null, parentMapping);
}
//獲取下一個結(jié)果集警没,并封裝到包裝類中
rsw = getNextResultSet(stmt);
//清空所有的嵌套結(jié)果對象
cleanUpAfterHandlingResultSet();
//每處理完一次匈辱,結(jié)果集數(shù)量+1
resultSetCount++;
}
}
//如果multipleResults只有一個元素,只會返回該元素對象杀迹;否則返回multipleResult
return collapseSingleResultList(multipleResults);
}
@Override
public <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling cursor results").object(mappedStatement.getId());
//獲取第一個結(jié)果集對象亡脸,并包裝起來
ResultSetWrapper rsw = getFirstResultSet(stmt);
//獲取ResultMap標(biāo)簽對象集合
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
//獲取集合的元素數(shù)量
int resultMapCount = resultMaps.size();
//驗證ResultMap標(biāo)簽對象數(shù)量,如果rsw不為null且ResultMapCount小于1,就會拋出異常
validateResultMapsCount(rsw, resultMapCount);
//檢查集合是否為1
if (resultMapCount != 1) {
//游標(biāo)結(jié)果不能映射到多個ResultMap標(biāo)簽對象
throw new ExecutorException("Cursor results cannot be mapped to multiple resultMaps");
}
//獲取唯一的一個ResultMap標(biāo)簽對象
ResultMap resultMap = resultMaps.get(0);
//返回默認(rèn)的mybatis游標(biāo)實例
return new DefaultCursor<>(this, resultMap, rsw, rowBounds);
}
/**
* 獲取第一個結(jié)果集
* @param stmt SQL腳本容器
* @return 結(jié)果集包裝類對象
*/
private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
//獲取結(jié)果集
ResultSet rs = stmt.getResultSet();
//如果結(jié)果集為null
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)
//前進(jìn)得到第一個結(jié)果集以防驅(qū)動不返回結(jié)果集的第一個結(jié)果
/**
* getMoreResults:移動到Statement對象的下一個結(jié)果,如果下一個結(jié)果是ResultSet對象树酪,返回true,
* 如果是一個更新記錄數(shù)或者已經(jīng)沒有更多的結(jié)果時浅碾,返回false
*/
if (stmt.getMoreResults()) {
//獲取結(jié)果集
rs = stmt.getResultSet();
} else {
//如果沒有結(jié)果集
//getUpdateCount:更新記錄數(shù),沒有時為-1
if (stmt.getUpdateCount() == -1) {
/**
* 當(dāng)((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))
* 就表示已經(jīng)沒有更多結(jié)果
*/
// no more results. Must be no resultset
break;
}
}
}
//如果結(jié)果集不為null续语,就包裝起來返回出去垂谢;否則,返回null
return rs != null ? new ResultSetWrapper(rs, configuration) : null;
}
/**
* 獲取下一個結(jié)果集
* @param stmt SQL腳本容器
* @return 結(jié)果集包裝類對象
*/
private ResultSetWrapper getNextResultSet(Statement stmt) {
// Making this method tolerant of bad JDBC drivers
//使用這個方法能增強(qiáng)對JDBC驅(qū)動的容錯率
try {
//檢索這個數(shù)據(jù)庫是否支持從一個單一調(diào)用方法執(zhí)行獲得多個結(jié)果集對象
if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {
// Crazy Standard JDBC way of determining if there are more results
//瘋狂的標(biāo)準(zhǔn)JDBC確定是否有更多結(jié)果的方法
//!stmt.getMoreResults() && stmt.getUpdateCount() == -1:表示已經(jīng)沒有更多結(jié)果
//如果有更多結(jié)果
if (!(!stmt.getMoreResults() && stmt.getUpdateCount() == -1)) {
//獲取結(jié)果集
ResultSet rs = stmt.getResultSet();
//如果結(jié)果集對象不為null
if (rs == null) {
//遞歸嘗試重新獲取下個一個結(jié)果集
return getNextResultSet(stmt);
} else {
//將結(jié)果集對象包裝起來返回
return new ResultSetWrapper(rs, configuration);
}
}
}
} catch (Exception e) {
// Intentionally ignored.
}
return null;
}
/**
* 關(guān)閉結(jié)果集,捕捉SQLException并不作任何處理
* @param rs 結(jié)果集
*/
private void closeResultSet(ResultSet rs) {
try {
//如果結(jié)果集不為null
if (rs != null) {
//關(guān)閉
rs.close();
}
} catch (SQLException e) {
// ignore 捕捉SQLException并不作任何處理
}
}
/**
* 清空所有的嵌套結(jié)果對象
*/
private void cleanUpAfterHandlingResultSet() {
nestedResultObjects.clear();
}
/**
* 驗證ResultMap標(biāo)簽對象數(shù)量,如果rsw不為null且ResultMapCount小于1疮茄,就會拋出異常
* @param rsw 結(jié)果集包裝類對象
* @param resultMapCount ResultMap標(biāo)簽對象數(shù)量
*/
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.");
}
}
/**
* 構(gòu)建出來的結(jié)果對象,如果父級結(jié)果屬性映射不為null滥朱,會將結(jié)果對象賦值到父級結(jié)果屬性對應(yīng)的結(jié)果對象中,
* 否則將結(jié)果對象加入到reusltHandler中力试。最后從reusltHandler中取的最終的結(jié)果對象加入到多個結(jié)果
* 對象集合中
* @param rsw 結(jié)果集包裝對象
* @param resultMap resultMap標(biāo)簽對象
* @param multipleResults 多個結(jié)果對象集合
* @param parentMapping 父級結(jié)果屬性映射
* @throws SQLException
*/
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
try {
//如果 父級結(jié)果屬性映射不為null
if (parentMapping != null) {
/**
* 構(gòu)建出來的結(jié)果對象,如果父級結(jié)果屬性映射不為null徙邻,會將結(jié)果對象賦值到父級結(jié)果屬性對應(yīng)的結(jié)果對象中,
* 否則將結(jié)果對象加入到reusltHandler中
*/
//這里因為paranetMapping已經(jīng)確定不為null了畸裳,所以resultHandler傳入null也不會有問題缰犁。
handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
} else {
//如果結(jié)果處理器對象為null
if (resultHandler == null) {
//創(chuàng)建一個默認(rèn)結(jié)果處理類對象
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
/**
* 構(gòu)建出來的結(jié)果對象,如果父級結(jié)果屬性映射不為null,會將結(jié)果對象賦值到父級結(jié)果屬性對應(yīng)的結(jié)果對象中,
* 否則將結(jié)果對象加入到reusltHandler中
*/
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
//將結(jié)果對象加入到多個結(jié)果對象集合中
multipleResults.add(defaultResultHandler.getResultList());
} else {
/**
* 構(gòu)建出來的結(jié)果對象,如果父級結(jié)果屬性映射不為null帅容,會將結(jié)果對象賦值到父級結(jié)果屬性對應(yīng)的結(jié)果對象中薇芝,
* 否則將結(jié)果對象加入到reusltHandler中
*/
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// issue #228 (close resultsets)
//關(guān)閉結(jié)果集,捕捉SQLException并不作任何處理
closeResultSet(rsw.getResultSet());
}
}
/**
* 折疊只有一個結(jié)果列表
* @param multipleResults 存放著多個結(jié)果的集合
* @return 如果multipleResults只有一個元素,只會返回該元素對象丰嘉;否則返回multipleResult
*/
@SuppressWarnings("unchecked")
private List<Object> collapseSingleResultList(List<Object> multipleResults) {
return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults;
}
//
// HANDLE ROWS FOR SIMPLE RESULTMAP
//
/**
* 構(gòu)建出來的結(jié)果對象,如果父級結(jié)果屬性映射不為null夯到,會將結(jié)果對象賦值到父級結(jié)果屬性對應(yīng)的結(jié)果對象中,
* 否則將結(jié)果對象加入到reusltHandler中
* @param rsw 結(jié)果集包裝類對象
* @param resultMap resultMap標(biāo)簽信息封裝類對象
* @param resultHandler 一般為 {@link DefaultResultHandler} 實例
* @param rowBounds mybatis的分頁
* @param parentMapping 父級結(jié)果屬性映射
*/
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
//如果存在嵌套的resultMap
if (resultMap.hasNestedResultMaps()) {
//確保沒有超過分頁行范圍
ensureNoRowBounds();
//檢查是否可以使用resultHandler
checkResultHandler();
//為嵌套的ResultMap標(biāo)簽對象饮亏,將構(gòu)建出來的結(jié)果對象加入到reusltHandler中
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
// 根據(jù)結(jié)果集包裝類對象和簡單的ResultMap標(biāo)簽對象耍贾,構(gòu)建成結(jié)果對象并加入到resultHandler中
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
/**
* 確保沒有超過分頁行范圍
* <p>
* 只有當(dāng)isSafeRowsEnable(允許在嵌套語句中使用行分界(RowBounds),默認(rèn)為false路幸,不允許)為ture的時候荐开,才會檢查 {@link #rowBounds}的行范圍是否超過最大值和最小值,超過時會拋出異常简肴。
* </p>
*/
private void ensureNoRowBounds() {
//isSafeRowsEnable:允許在嵌套語句中使用行分界(RowBounds)晃听,默認(rèn)為false,不允許
//當(dāng)允許時砰识,會判斷rowBound的范圍是否超過最大值和最小值能扒,超過時會拋出異常。
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.");
}
}
/**
* 檢查是否可以使用resultHandler
*/
protected void checkResultHandler() {
//SafeResultHandlerEnabled:允許在嵌套語句中使用分頁(ResultHandler)辫狼。如果允許使用則設(shè)置為 false初斑。
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.");
}
}
/**
* 根據(jù)結(jié)果集包裝類對象和簡單的ResultMap標(biāo)簽對象,構(gòu)建成結(jié)果對象
* @param rsw 結(jié)果集包裝類對象
* @param resultMap ResultMap標(biāo)簽對象
* @param resultHandler 結(jié)果處理器
* @param rowBounds Mybatis的分頁對象
* @param parentMapping 父級屬性結(jié)果映射
* @throws SQLException
*/
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
//新建一個默認(rèn)的結(jié)果上下文
DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
//獲取結(jié)果集
ResultSet resultSet = rsw.getResultSet();
////跳過rowBounds.offset記錄數(shù)
skipRows(resultSet, rowBounds);
//如果還有結(jié)果需要處理 而且 結(jié)果集還沒有關(guān)閉 而且 結(jié)果集還有數(shù)據(jù)
while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
//逐層解析resultMap鑒別器膨处,取得最終的ResultMap標(biāo)簽對象
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
//根據(jù)rsw 和resultMap 構(gòu)建出 {@link ResultMap#getType()} 類型的對象
Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
/**
* 保存對象,如果parentMaping 不為null,就將結(jié)果對象添加到parentMapping
* 的metaObject中;否則见秤,調(diào)用結(jié)果處理器,將結(jié)果對象添加到結(jié)果處理器中
*/
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
}
/**
* 保存對象,如果 {@code parentMaping} 不為null,就將結(jié)果對象添加到 {@code parentMapping}
* 的metaObject中;否則真椿,調(diào)用結(jié)果處理器鹃答,將結(jié)果對象添加到結(jié)果處理器中
* @param resultHandler 結(jié)果處理類對象
* @param resultContext 結(jié)果上下文
* @param rowValue resultMap對象
* @param parentMapping 結(jié)果映射
* @param rs 結(jié)果集
*/
private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
//如果上一層的ResultMapping對象不為null
if (parentMapping != null) {
//將嵌套對象記錄到外層元對象相應(yīng)的屬性中
linkToParents(rs, parentMapping, rowValue);
} else {
//調(diào)用結(jié)果處理器,將結(jié)果對象添加到結(jié)果處理器中
callResultHandler(resultHandler, resultContext, rowValue);
}
}
/**
* 調(diào)用結(jié)果處理器突硝,將結(jié)果對象添加到結(jié)果處理器中
* @param resultHandler 結(jié)果處理器测摔,
* @param resultContext 結(jié)果上下文
* @param rowValue 結(jié)果對象
*/
@SuppressWarnings("unchecked" /* because ResultHandler<?> is always ResultHandler<Object>*/)
private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {
//設(shè)置下一個結(jié)果對象
resultContext.nextResultObject(rowValue);
/**
* 如果是DefaultResultHandler,就會將結(jié)果對象添加到內(nèi)部的List對象中
* 如果是DefaultMapResultHandler狞换,會將結(jié)果對象添加到內(nèi)部的Map對象中
*/
((ResultHandler<Object>) resultHandler).handleResult(resultContext);
}
/**
* 是否還有結(jié)果需要處理
* @param context 結(jié)果上下文
* @param rowBounds mybatis的分頁對象
* @return 當(dāng) {@code context} 沒有停止避咆,且 {@code context} 的resultCount小于 {@code rowBounds} 的 limit是,為true修噪,否則為false
*/
private boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) {
return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
}
/**
* 跳過rowBounds.offset記錄數(shù)
* @param rs 結(jié)果集
* @param rowBounds Mybatis的分頁對象
* @throws SQLException
*/
private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {
//ResultSet.TYPE_FORWORD_ONLY 結(jié)果集的游標(biāo)只能向下滾動
if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
//absolute:將指針移動到此 ResultSet 對象的給定行編號查库。
rs.absolute(rowBounds.getOffset());
}
} else {
//通過ResultSet的next()改變rs的游標(biāo)位置直到達(dá)到rowBounds設(shè)置的offset
for (int i = 0; i < rowBounds.getOffset(); i++) {
if (!rs.next()) {
break;
}
}
}
}
//
// GET VALUE FROM ROW FOR SIMPLE RESULT MAP
//
/**
* 根據(jù) {@code rsw} 和 {@code resultMap} 構(gòu)建出 {@link ResultMap#getType()} 類型的對象
* @param rsw 結(jié)果集包裝類對象
* @param resultMap Mapper.xml的resultMap標(biāo)簽信息封裝類對象
* @param columnPrefix 列名前綴
* @return {@link ResultMap#getType()} 類型的對象
*/
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
//用來表示需要懶加載的屬性集,本質(zhì)是一個HashMap
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
//根據(jù) {@code rsw} 和 {@code resultMap} 的配置構(gòu)建結(jié)果對象
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
//結(jié)果對象不為null但沒有對應(yīng)結(jié)果類型的TypeHandler
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
//構(gòu)建結(jié)果元對象
final MetaObject metaObject = configuration.newMetaObject(rowValue);
//當(dāng)前結(jié)果對象是否使用了非無參構(gòu)造函數(shù)進(jìn)行構(gòu)建的標(biāo)記
boolean foundValues = this.useConstructorMappings;
//是否可以應(yīng)用自動映射
if (shouldApplyAutomaticMappings(resultMap, false)) {
//對未能被映射列名映射關(guān)系集合進(jìn)行嘗試賦值黄琼,將結(jié)果集對應(yīng)數(shù)據(jù)賦值到結(jié)果對象對應(yīng)的屬性中
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
// applyPropertyMappings:根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象樊销,并賦值到結(jié)果對象中
// 這時候的foundValue表示只有一個根據(jù)屬性映射和結(jié)果集成功構(gòu)建出對應(yīng)的目標(biāo)對象整慎,foundValue就為true
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
/**
* isReturnInstanceForEmptyRow:
* 當(dāng)返回行的所有列都是空時,MyBatis默認(rèn)返回 null围苫。
* 當(dāng)開啟這個設(shè)置時,MyBatis會返回一個空實例.請注意裤园,它也適用于嵌套的結(jié)果集(如集合或關(guān)聯(lián)).
* (新增于 3.4.2)
*/
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
/**
* 是否可以應(yīng)用自動映射
* @param resultMap Mapper.xml的resultMap標(biāo)簽信息封裝類對象
* @param isNested 是否是嵌套的
* @return 可以應(yīng)用自動映射,返回true剂府;否則返回false
*/
private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {
//如果配置了自動映射標(biāo)記
if (resultMap.getAutoMapping() != null) {
//自動映射
return resultMap.getAutoMapping();
} else {
//如果是嵌套
if (isNested) {
//AutoMappingBehavior.FULL表示: 自動映射任意復(fù)雜的結(jié)果集(無論是否嵌套)拧揽。
return AutoMappingBehavior.FULL == configuration.getAutoMappingBehavior();
} else {
//AutoMappingBehavior.NODE:取消自動映射
//AutoMappingBehavior.PARTIAL:自動映射沒有定義嵌套結(jié)果集映射的結(jié)果集
return AutoMappingBehavior.NONE != configuration.getAutoMappingBehavior();
}
}
}
//
// PROPERTY MAPPINGS
//
/**
* 根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象,并賦值到結(jié)果對象中
* @param rsw 結(jié)果集包裝類對象
* @param resultMap Mapper.xml的resultMap標(biāo)簽信息封裝類對象
* @param metaObject 結(jié)果元對象
* @param lazyLoader 用來表示需要懶加載的屬性集腺占,本質(zhì)是一個HashMap
* @param columnPrefix 列名前綴
* @return 成功根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象的標(biāo)記淤袜,哪怕只有一個成功,都會為true
*/
private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
throws SQLException {
//獲取映射列名集合
final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
//成功根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象的標(biāo)記衰伯,哪怕只有一個成功铡羡,都會為true
boolean foundValues = false;
//獲取屬性映射關(guān)系集合,該集合不包括標(biāo)記為構(gòu)造函數(shù)的屬性映射關(guān)系
final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
//遍歷屬性映射關(guān)系
for (ResultMapping propertyMapping : propertyMappings) {
//拼接前綴與列名
String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
//如果配置了嵌套的resultMapId
if (propertyMapping.getNestedResultMapId() != null) {
// the user added a column attribute to a nested result map, ignore it
//用戶添加一個列屬性是一個嵌套映射結(jié)果,忽略它;
column = null;
}
/**
* 如果屬性映射存在組合ResultMaping列表
* 或者 column不為null且映射列名集合中包含column
* 或者 屬性映射配置了用于加載復(fù)雜類型的結(jié)果集
*/
if (propertyMapping.isCompositeResult()
|| (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
|| propertyMapping.getResultSet() != null) {
//根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象
Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
// issue #541 make property optional
//獲取屬性映射的屬性名
final String property = propertyMapping.getProperty();
//如果沒有配置屬性名
if (property == null) {
//跳過該屬性映射
continue;
//如果目標(biāo)對象是一個標(biāo)記為待定的對象
} else if (value == DEFERRED) {
//成功根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象的標(biāo)記設(shè)置為true
foundValues = true;
continue;
}
//如果目標(biāo)對象不為null
if (value != null) {
//成功根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象的標(biāo)記設(shè)置為true
foundValues = true;
}
/**
* isCallSetterOnNulls:
* 指定當(dāng)結(jié)果集中值為 null 的時候是否調(diào)用映射對象的 setter(map 對象時為 put)方法意鲸,
* 這在依賴于 Map.keySet() 或 null 值初始化的時候比較有用烦周。
* 注意基本類型(int、boolean 等)是不能設(shè)置成 null 的怎顾。
*/
//如果對象不為null,或者指定當(dāng)結(jié)果集中值為null的時候允許調(diào)用映射對象的setter(map對象時為 put)方法,且不是基本類型
if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {
// gcode issue #377, call setter on nulls (value is not 'found')
//將value賦值到結(jié)果對象中的mapping.property屬性中
metaObject.setValue(property, value);
}
}
}
return foundValues;
}
/**
* 根據(jù)結(jié)果集和屬性映射對應(yīng)的目標(biāo)對象
* @param rs 結(jié)果集
* @param metaResultObject 結(jié)果元對象
* @param propertyMapping 屬性映射
* @param lazyLoader 用來表示需要懶加載的屬性集读慎,本質(zhì)是一個HashMap
* @param columnPrefix 列名前綴
* @return 根據(jù)結(jié)果集和屬性映射構(gòu)建對應(yīng)的目標(biāo)對象
*/
private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
throws SQLException {
//如果屬性映射配置了嵌套select標(biāo)簽Id
if (propertyMapping.getNestedQueryId() != null) {
//構(gòu)建帶有嵌套查詢屬性的值對象
return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
//如果加載復(fù)雜類型的結(jié)果集
} else if (propertyMapping.getResultSet() != null) {
// 添加 {propertyMapping待定關(guān)系到待定關(guān)系映射集合 {@link #pendingRelations}
addPendingChildRelation(rs, metaResultObject, propertyMapping); // TODO is that OK?
//返回標(biāo)記著待定的對象
return DEFERRED;
} else {
//屬性映射的默認(rèn)情況處理
//獲取屬性映射的TypeHandler
final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
//獲取屬性映射的列名,并拼接列名前綴
final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
//從 ResultSet 中取出columnName對應(yīng)數(shù)據(jù)杆勇,然后轉(zhuǎn)換為 java 對象
return typeHandler.getResult(rs, column);
}
}
/**
* 獲取未能被映射列名映射關(guān)系集合
* @param rsw 結(jié)果集包裝類對象
* @param resultMap Mapper.xml的resultMap標(biāo)簽信息封裝類對象
* @param metaObject 結(jié)果元對象
* @param columnPrefix 列名
* @return 未能被映射列名映射關(guān)系集合
* @throws SQLException
*/
private List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
//構(gòu)建autoMappingCache的Key
final String mapKey = resultMap.getId() + ":" + columnPrefix;
//獲取mapKey的自動映射集合
List<UnMappedColumnAutoMapping> autoMapping = autoMappingsCache.get(mapKey);
//如果自動映射集合為null
if (autoMapping == null) {
//初始化自動映射集合
autoMapping = new ArrayList<>();
//獲取未被映射的列名集合
final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
//遍歷未被映射的列名集合
for (String columnName : unmappedColumnNames) {
//將列名當(dāng)作屬性名
String propertyName = columnName;
//如果列名前綴不為null且不是空字符串
if (columnPrefix != null && !columnPrefix.isEmpty()) {
// When columnPrefix is specified,
// ignore columns without the prefix.
//當(dāng)列名前綴被指定了贪壳,就忽略沒有指定前綴的列
//列名是以columnPrefix開頭
if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
//去掉columnPrefix賦值給propertyName
propertyName = columnName.substring(columnPrefix.length());
} else {
//忽略沒有指定前綴的列
continue;
}
}
/**
* isMapUnderscoreToCamelCase:是否開啟自動駝峰命名規(guī)則(camel case)映射饱亿,
* 即從經(jīng)典數(shù)據(jù)庫列名 A_COLUMN 到經(jīng)典 Java 屬性名 aColumn 的類似映射
*/
//查看結(jié)果對象是否存在propertyName屬性,存在便會返回該屬性名
final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
//如果屬性不為null且結(jié)果對象有這個屬性的setter方法
if (property != null && metaObject.hasSetter(property)) {
//如果配置的映射屬性名中有這個屬性
if (resultMap.getMappedProperties().contains(property)) {
//跳過
continue;
}
//獲取結(jié)果對象的property的setter方法的參數(shù)類型
final Class<?> propertyType = metaObject.getSetterType(property);
//如果存在propertyType和columnName的jdbcType的TypeHandler
if (typeHandlerRegistry.hasTypeHandler(propertyType, rsw.getJdbcType(columnName))) {
//獲取propertyType和columnName的TypeHandler
final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
//構(gòu)建UnMappedColumnAutoMapping對象蚜退,并添加到autoMapping中
autoMapping.add(new UnMappedColumnAutoMapping(columnName, property, typeHandler, propertyType.isPrimitive()));
} else {
//不存在propertyType和columnName的jdbcType的TypeHandler時
/**
* AutoMappingUnknownColumnBehavior: 指定發(fā)現(xiàn)自動映射目標(biāo)未知列(或者未知屬性類型)的行為
* NONE:不做任何反應(yīng),默認(rèn)
* WARNING:輸出提醒日志
* FAILING:映射失敗 (拋出 SqlSessionException)
*/
//AutoMappingUnknownColumnBehavior為枚舉類,doAction為枚舉方法彪笼。
/**
* 根據(jù)配置的AutoMappingUnknownColumnBehavior枚舉類钻注,作出相應(yīng)的處理,要么什么都不做配猫,要
* 么輸出提醒日志幅恋,要么拋出SqlSessionException
*/
configuration.getAutoMappingUnknownColumnBehavior()
.doAction(mappedStatement, columnName, property, propertyType);
}
} else {
//屬性為null或者結(jié)果對象沒有這個屬性的setter方法
/**
* 根據(jù)配置的AutoMappingUnknownColumnBehavior枚舉類,作出相應(yīng)的處理泵肄,要么什么都不做捆交,要
* 么輸出提醒日志,要么拋出SqlSessionException
*/
configuration.getAutoMappingUnknownColumnBehavior()
.doAction(mappedStatement, columnName, (property != null) ? property : propertyName, null);
}
}
//保存結(jié)果對象的自動自動映射集合
autoMappingsCache.put(mapKey, autoMapping);
}
return autoMapping;
}
/**
* 對未能被映射列名映射關(guān)系集合進(jìn)行嘗試賦值腐巢,將結(jié)果集對應(yīng)數(shù)據(jù)賦值到結(jié)果對象對應(yīng)的屬性中
* @param rsw 結(jié)果集包裝類對象
* @param resultMap Mapper.xml的resultMap標(biāo)簽信息封裝類對象
* @param metaObject 結(jié)果元對象
* @param columnPrefix 列名前綴
* @return 成功根據(jù)自動映射關(guān)系集合的元素構(gòu)建出指定java類對象標(biāo)記品追,返回true;否則返回false
*/
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
//獲取未能被映射列名映射關(guān)系集合
List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
//成功根據(jù)自動映射關(guān)系集合的元素構(gòu)建出指定java類對象標(biāo)記
boolean foundValues = false;
//如果自動映射關(guān)系集合不為空
if (!autoMapping.isEmpty()) {
//遍歷自動映射關(guān)系集合
for (UnMappedColumnAutoMapping mapping : autoMapping) {
//從 ResultSet 中取出columnName對應(yīng)數(shù)據(jù)冯丙,然后轉(zhuǎn)換為 java 對象
final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
//如果對象不為null
if (value != null) {
//只要有一個成功根據(jù)自動映射關(guān)系集合的元素構(gòu)建出指定java類對象肉瓦,標(biāo)記就會變成true
foundValues = true;
}
/**
* isCallSetterOnNulls:
* 指定當(dāng)結(jié)果集中值為 null 的時候是否調(diào)用映射對象的 setter(map 對象時為 put)方法,
* 這在依賴于 Map.keySet() 或 null 值初始化的時候比較有用。
* 注意基本類型(int泞莉、boolean 等)是不能設(shè)置成 null 的哪雕。
*/
//如果對象不為null,或者指定當(dāng)結(jié)果集中值為null的時候允許調(diào)用映射對象的setter(map對象時為 put)方法,且不是基本類型
if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
// gcode issue #377, call setter on nulls (value is not 'found')
//將value賦值到結(jié)果對象中的mapping.property屬性中
metaObject.setValue(mapping.property, value);
}
}
}
return foundValues;
}
// MULTIPLE RESULT SETS
/**
* 將嵌套對象記錄到外層元對象相應(yīng)的屬性中
* @param rs 結(jié)果集
* @param parentMapping 結(jié)果映射
* @param rowValue 上一次嵌套的resultMap對象所構(gòu)建出來的對象
*/
private void linkToParents(ResultSet rs, ResultMapping parentMapping, Object rowValue) throws SQLException {
//將外鍵對應(yīng)結(jié)果集中的對象以及嵌套列名綁定到CacheKey對象中
CacheKey parentKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getForeignColumn());
//獲取該CacheKey對象對應(yīng)的PendingRelation列表
List<PendingRelation> parents = pendingRelations.get(parentKey);
//如果該列表不為null
if (parents != null) {
//遍歷PendingRelation列表
for (PendingRelation parent : parents) {
//如果列表中的每一項不為null 且 上一次嵌套的resultMap對象所構(gòu)建出來的對象也不為null
if (parent != null && rowValue != null) {
/**
* 上一次嵌套的resultMap對象所構(gòu)建出來的對象放入元數(shù)據(jù)類型對象的相應(yīng)屬性中,如果為集合
* 則在集合屬性中添加該rowValue;如果不為集合鲫趁,則直接將該屬性設(shè)置為rowValue
*/
linkObjects(parent.metaObject, parent.propertyMapping, rowValue);
}
}
}
}
/**
* 添加 {@code parentMapping} 待定關(guān)系到待定關(guān)系映射集合 {@link #pendingRelations}
* @param rs 結(jié)果集對象
* @param metaResultObject 結(jié)果元對象
* @param parentMapping 父級屬性映射
*/
private void addPendingChildRelation(ResultSet rs, MetaObject metaResultObject, ResultMapping parentMapping) throws SQLException {
//為多個結(jié)果數(shù)據(jù)創(chuàng)建緩存Key
CacheKey cacheKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getColumn());
//創(chuàng)建一個待定關(guān)系類對象
PendingRelation deferLoad = new PendingRelation();
//將結(jié)果元對象賦值到待定關(guān)系類對象中
deferLoad.metaObject = metaResultObject;
//將父級屬性映射賦值到待定關(guān)系類對象中
deferLoad.propertyMapping = parentMapping;
//從待定關(guān)系映射集合中獲取cacheKey對應(yīng)的待定關(guān)系集合斯嚎,如果沒有對應(yīng)的待定關(guān)系集合會新建一個集合返回出去。
List<PendingRelation> relations = pendingRelations.computeIfAbsent(cacheKey, k -> new ArrayList<>());
// issue #255
//添加待定關(guān)系到集合中
relations.add(deferLoad);
//從之前整合的結(jié)果映射對象映射集合中獲取parentMapping.getResultSet()配置對應(yīng)結(jié)果映射
ResultMapping previous = nextResultMaps.get(parentMapping.getResultSet());
//如果沒有找對應(yīng)的結(jié)果映射
if (previous == null) {
//將結(jié)果映射加入到之前整合的結(jié)果映射對象映射集合中
nextResultMaps.put(parentMapping.getResultSet(), parentMapping);
} else {
//如果獲取出來的映射結(jié)果和paraentMapping不是同一對象
if (!previous.equals(parentMapping)) {
//兩個不同的屬性不可以映射到相同的結(jié)果集
throw new ExecutorException("Two different properties are mapped to the same resultSet");
}
}
}
/**
* 為多個結(jié)果數(shù)據(jù)創(chuàng)建緩存Key
* @param rs 結(jié)果集
* @param resultMapping 結(jié)果屬性映射
* @param names 列名
* @param columns 列名
* @return 對應(yīng)多個結(jié)果數(shù)據(jù)緩存Key
*/
private CacheKey createKeyForMultipleResults(ResultSet rs, ResultMapping resultMapping, String names, String columns) throws SQLException {
//新建一個緩存Key對象
CacheKey cacheKey = new CacheKey();
//將結(jié)果屬性映射作為緩存Key的一部分的
cacheKey.update(resultMapping);
//如果兩個列名參數(shù)都不為null
if (columns != null && names != null) {
//因為有可能指代多個列名挨厚,所以用逗號進(jìn)行分割
String[] columnsArray = columns.split(",");
///因為有可能指代多個列名孝扛,所以用逗號進(jìn)行分割
String[] namesArray = names.split(",");
//遍歷列名數(shù)組
for (int i = 0; i < columnsArray.length; i++) {
//獲取列名對應(yīng)結(jié)果數(shù)據(jù)
Object value = rs.getString(columnsArray[i]);
if (value != null) {
//將列名映射作為緩存Key的一部分的
cacheKey.update(namesArray[i]);
//將列名對應(yīng)結(jié)果數(shù)據(jù)作為緩存Key的一部分的
cacheKey.update(value);
}
}
}
return cacheKey;
}
//
// INSTANTIATION & CONSTRUCTOR MAPPING
//
/**
* 根據(jù) {@code rsw} 和 {@code resultMap} 的配置構(gòu)建結(jié)果對象
* @param rsw 結(jié)果集包裝類對象
* @param resultMap Mapper.xml的resultMap標(biāo)簽信息封裝類對象
* @param lazyLoader 用來表示需要懶加載的屬性集,本質(zhì)是一個HashMap
* @param columnPrefix 列名前綴
* @return {@link ResultMap#getType()} 類型的對象
*/
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
this.useConstructorMappings = false; // reset previous mapping result 重置上一個映射結(jié)果
//構(gòu)造函數(shù)參數(shù)類型集合
final List<Class<?>> constructorArgTypes = new ArrayList<>();
//構(gòu)造函數(shù)參數(shù)集合
final List<Object> constructorArgs = new ArrayList<>();
//取得構(gòu)造函數(shù)所需的參數(shù)值去創(chuàng)建結(jié)果對象
Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
//如果結(jié)果對象不為null但沒有結(jié)果類型對應(yīng)的TypeHandler
if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
//獲取屬性結(jié)果映射關(guān)系集合幽崩,該集合不包括標(biāo)記為構(gòu)造函數(shù)的結(jié)果映射關(guān)系
final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
//變量屬性結(jié)果映射關(guān)系
for (ResultMapping propertyMapping : propertyMappings) {
// issue gcode #109 && issue #149
//如果配置了嵌套查詢而且還配置了該屬性為懶加載
if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
//將reusltObject改造成代理對象苦始,從而處理懶加載
resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
break;
}
}
}
//如果當(dāng)前結(jié)果對象不為null且構(gòu)造函數(shù)類型集合不為空,就將useConstructorMappings賦值為true
this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping result 設(shè)置當(dāng)前結(jié)果映射關(guān)系
return resultObject;
}
/**
* 取得構(gòu)造函數(shù)所需的參數(shù)值去創(chuàng)建結(jié)果對象
* @param rsw 結(jié)果集包裝類對象
* @param resultMap Mapper.xml的resultMap標(biāo)簽信息封裝類對象
* @param constructorArgTypes 構(gòu)造函數(shù)參數(shù)類型集合
* @param constructorArgs 構(gòu)造函數(shù)參數(shù)集合
* @param columnPrefix 列名前綴
* @return {@link ResultMap#getType()} 類型的對象
*/
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
throws SQLException {
//獲取結(jié)果對象類型
final Class<?> resultType = resultMap.getType();
//構(gòu)建結(jié)果對象類型的元對象
final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
//獲取構(gòu)造函數(shù)映射關(guān)系
final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
//如果存在對應(yīng)的TypeHandler
if (hasTypeHandlerForResultObject(rsw, resultType)) {
//創(chuàng)建原始的結(jié)果對象
return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
//構(gòu)造函數(shù)映射關(guān)系不為空
} else if (!constructorMappings.isEmpty()) {
//根據(jù)構(gòu)造函數(shù)映射構(gòu)建的結(jié)果對象
return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
//如果resultType是接口或者resultType有默認(rèn)的構(gòu)造函數(shù)
} else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
//讓objectFactory創(chuàng)建通過默認(rèn)構(gòu)造函數(shù)resultType對象
return objectFactory.create(resultType);
//是否可以應(yīng)用自動映射
} else if (shouldApplyAutomaticMappings(resultMap, false)) {
//取得構(gòu)造函數(shù)所需的參數(shù)值去創(chuàng)建結(jié)果對象(自動映射)
return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs);
}
throw new ExecutorException("Do not know how to create an instance of " + resultType);
}
/**
* 根據(jù)構(gòu)造函數(shù)映射構(gòu)建的結(jié)果對象
* @param rsw 結(jié)果集包裝類對象
* @param resultType 結(jié)果類型
* @param constructorMappings 構(gòu)造函數(shù)參數(shù)映射關(guān)系集合
* @param constructorArgTypes 構(gòu)造函數(shù)參數(shù)類型集合
* @param constructorArgs 構(gòu)造函數(shù)參數(shù)集合
* @param columnPrefix 列名前綴
* @return 如果有構(gòu)建出構(gòu)造函數(shù)參數(shù)對象慌申,就讓objectFactory根據(jù)
* 構(gòu)造函數(shù)參數(shù)創(chuàng)建resultType對象陌选,否則返回null
*/
Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType, List<ResultMapping> constructorMappings,
List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) {
//有構(gòu)建出構(gòu)造函數(shù)參數(shù)對象的標(biāo)記
boolean foundValues = false;
//遍歷構(gòu)造函數(shù)參數(shù)映射關(guān)系
for (ResultMapping constructorMapping : constructorMappings) {
//獲取構(gòu)造函數(shù)參數(shù)映射關(guān)系對應(yīng)java類型
final Class<?> parameterType = constructorMapping.getJavaType();
//獲取構(gòu)造函數(shù)參數(shù)映射關(guān)系對應(yīng)的列名
final String column = constructorMapping.getColumn();
final Object value;
try {
//如果構(gòu)造函數(shù)參數(shù)映射關(guān)系配置了嵌套查詢的select標(biāo)簽ID
if (constructorMapping.getNestedQueryId() != null) {
//獲取嵌套查詢構(gòu)造函數(shù)參數(shù)值
value = getNestedQueryConstructorValue(rsw.getResultSet(), constructorMapping, columnPrefix);
//如果構(gòu)造函數(shù)參數(shù)映射關(guān)系配置了嵌套的resultMapId
} else if (constructorMapping.getNestedResultMapId() != null) {
//獲取構(gòu)造函數(shù)參數(shù)映射關(guān)系配置的resultMapId對應(yīng)的ResultMap對象
final ResultMap resultMap = configuration.getResultMap(constructorMapping.getNestedResultMapId());
//根據(jù)rsw 和 resultMap構(gòu)建出 {@link ResultMap#getType()} 類型的對象
value = getRowValue(rsw, resultMap, getColumnPrefix(columnPrefix, constructorMapping));
//不存在嵌套的情況
} else {
//獲取構(gòu)造函數(shù)參數(shù)映射的TypeHandler
final TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
//從 ResultSet 中取出columnName對應(yīng)數(shù)據(jù),然后轉(zhuǎn)換為 java 對象
value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));
}
} catch (ResultMapException | SQLException e) {
throw new ExecutorException("Could not process result for mapping: " + constructorMapping, e);
}
//將構(gòu)造函數(shù)參數(shù)類型添加到constructorArgTypes中
constructorArgTypes.add(parameterType);
//將構(gòu)造函數(shù)參數(shù)對象添加到construtorArgs中
constructorArgs.add(value);
//只要有一個構(gòu)造函數(shù)參數(shù)對象不為null咨油,foundValue都會為true
foundValues = value != null || foundValues;
}
//如果有構(gòu)建出構(gòu)造函數(shù)參數(shù)對象法瑟,就讓objectFactory根據(jù)構(gòu)造函數(shù)參數(shù)創(chuàng)建resultType對象酥夭,否則返回null
return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
}