【福利】關注微信公眾號:深夜程猿,回覆關鍵字即可獲取學習視訊、簡歷模版
Mybatis支援多結果集,也就是結果集中的元素也可以是結果集,返回結果集的時候會呼叫相應的結果集處理器來處理結果集。我們來從原始碼角度看看具體的實現原理
首先,在查詢操作,執行sql語句返回查詢結果集後,呼叫預設的結果集處理器handleResultSets方法
DefaultResultSetHandler#handleResultSets
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;
// 獲取第一個結果集,如果沒有結果集,那麼返回null
// 獲取第一個結果集在於知道sql語句要操作到哪些元素資料(表的列),會獲取到後設資料名稱、Java資料型別、JDBC資料型別
ResultSetWrapper rsw = getFirstResultSet(stmt);
// 獲取執行的sql配置的resultMap
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
// 一個resultMap對應一個結果集,依次遍歷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) {
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);
}
複製程式碼
我們看一下是怎麼獲取第一個結果集的
DefaultResultSetHandler#getFirstResultSet
private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
ResultSet rs = stmt.getResultSet();
while (rs == null) {
// 沒有結果集,也許是資料庫驅動還沒有返回第一個結果集
if (stmt.getMoreResults()) {
// 嘗試再一次獲取結果集
rs = stmt.getResultSet();
} else {
if (stmt.getUpdateCount() == -1) {
//rs == null && stmt.getUpdateCount() == -1表示驅動已經返回,沒有更多結果,沒有結果集
break;
}
}
}
return rs != null ? new ResultSetWrapper(rs, configuration) : null;
}
複製程式碼
ResultSetWrapper#建構函式
// 封裝結果集
public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {
super();
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.resultSet = rs;
final ResultSetMetaData metaData = rs.getMetaData();
final int columnCount = metaData.getColumnCount();
// 設定結果集的後設資料
for (int i = 1; i <= columnCount; i++) {
columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));
jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));
classNames.add(metaData.getColumnClassName(i));
}
}
複製程式碼
我們繼續看下handleResultSet(rsw, resultMap, multipleResults, null);
的具體實現
DefaultResultSetHandler #handleResultSet
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());
}
}
複製程式碼
接著看handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
的實現
DefaultResultSetHandler#handleRowValues
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
if (resultMap.hasNestedResultMaps()) { // 判斷resultMap是否有巢狀的resultMap
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
複製程式碼
先看下沒有巢狀resultMap的處理邏輯handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
DefaultResultSetHandler#handleRowValuesForSimpleResultMap
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);
// 處理行資料,並封裝成指定的resultType
Object rowValue = getRowValue(rsw, discriminatedResultMap);
// 快取物件,修改rowBounds的值
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
複製程式碼
再往下分析怎麼獲取行資料並封裝成指定的resultType
DefaultResultSetHandler#getRowValue
// 獲取行資料值
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
// 行資料物件不是null,並且沒有結果型別處理器
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
if (shouldApplyAutomaticMappings(resultMap, false)) {
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
}
// 應用resultMap的屬性對映配置,為行資料物件設定從資料庫獲取回來的值
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = (foundValues || configuration.isReturnInstanceForEmptyRow()) ? rowValue : null;
}
// 返回處理過的行資料物件
return rowValue;
}
複製程式碼
簡單分析了結果集的處理原理,它基本步驟:
- 解析SQL語句
- 執行SQL語句
- 根據SQL對映配置,比如resultMap或者resulType,resultSets等來對步驟2獲取回來的結果集處理
- 返回處理過的結果集