1. 程式人生 > 其它 >Mybatis原始碼之ResultSet結果集處理

Mybatis原始碼之ResultSet結果集處理

時序圖

詳細步驟

PreparedStatementHandler#query

@Override
public<E>List<E>query(Statementstatement,ResultHandlerresultHandler)throwsSQLException{
PreparedStatementps=(PreparedStatement)statement;
//執行SQL
ps.execute();
//結果集處理
returnresultSetHandler.handleResultSets(ps);
}

DefaultResultSetHandler#handleResultSets

/**
*處理statement得到的多結果集(也可能是單結果集,這是多結果集的一種簡化形式),最終得到結果列表
*
*handleResultSets方法完成了對多結果集的處理。但是對於每一個結果集的處理是由handleResultSet子方法實現的
*@paramstmtStatement語句
*@return結果列表
*@throwsSQLException
*/
@Override
publicList<Object>handleResultSets(Statementstmt)throwsSQLException{
ErrorContext.instance().activity("handlingresults").object(mappedStatement.getId());
//用以儲存處理結果的列表
finalList<Object>multipleResults=newArrayList<>();
//可能會有多個結果集,該變數用來對結果集進行計數
intresultSetCount=0;
//可能會有多個結果集,先取出第一個結果集
ResultSetWrapperrsw=getFirstResultSet(stmt);
//查詢語句對應的resultMap節點,可能含有多個
List<ResultMap>resultMaps=mappedStatement.getResultMaps();
intresultMapCount=resultMaps.size();
//合法性校驗(存在輸出結果集的情況下,resultMapCount不能為0)
validateResultMapsCount(rsw,resultMapCount);
//迴圈遍歷每一個設定了resultMap的結果集
while(rsw!=null&&resultMapCount>resultSetCount){
//獲得當前結果集對應的ResultMap
ResultMapresultMap=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用來描述物件屬性的對映關係)
ResultMappingparentMapping=nextResultMaps.get(resultSets[resultSetCount]);
if(parentMapping!=null){
//獲取被巢狀的resultMap編號
StringnestedResultMapId=parentMapping.getNestedResultMapId();
ResultMapresultMap=configuration.getResultMap(nestedResultMapId);
//處理巢狀對映
handleResultSet(rsw,resultMap,null,parentMapping);
}
rsw=getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}
//判斷是否為單結果集:如果是,則返回結果列表;如果不是則返回結果集列表
returncollapseSingleResultList(multipleResults);
}

DefaultResultSetHandler#handleResultSet

/**
*處理單一的結果集
*@paramrswResultSet的包裝
*@paramresultMapresultMap節點資訊
*@parammultipleResults用來儲存處理結果的列表
*@paramparentMapping
*@throwsSQLException
*/
privatevoidhandleResultSet(ResultSetWrapperrsw,ResultMapresultMap,List<Object>multipleResults,ResultMappingparentMapping)throwsSQLException{
try{
if(parentMapping!=null){//巢狀的結果
//向子方法闖入parentMapping。處理結果中的記錄
handleRowValues(rsw,resultMap,null,RowBounds.DEFAULT,parentMapping);
}else{//非巢狀的結果
if(resultHandler==null){
//defaultResultHandler能夠將結果物件聚合成一個列表返回
DefaultResultHandlerdefaultResultHandler=newDefaultResultHandler(objectFactory);
//處理結果中的記錄
handleRowValues(rsw,resultMap,defaultResultHandler,rowBounds,null);
//新增處理後的結果
multipleResults.add(defaultResultHandler.getResultList());
}else{
handleRowValues(rsw,resultMap,resultHandler,rowBounds,null);
}
}
}finally{
//issue#228(closeresultsets)
closeResultSet(rsw.getResultSet());
}
}

DefaultResultSetHandler#handleRowValuesForSimpleResultMap

/**
*處理非巢狀對映的結果
*@paramrsw結果集包裝
*@paramresultMap結果對映
*@paramresultHandler結果處理器
*@paramrowBounds翻頁限制條件
*@paramparentMapping父級結果對映
*@throwsSQLException
*/
privatevoidhandleRowValuesForSimpleResultMap(ResultSetWrapperrsw,ResultMapresultMap,ResultHandler<?>resultHandler,RowBoundsrowBounds,ResultMappingparentMapping)
throwsSQLException{
DefaultResultContext<Object>resultContext=newDefaultResultContext<>();
//當前要處理的結果集
ResultSetresultSet=rsw.getResultSet();
//根據翻頁配置,跳過指定的行
skipRows(resultSet,rowBounds);
//持續處理下一條結果,判斷條件為;還有結果需要處理&&結果集沒有關閉&&還有下一條結果
while(shouldProcessMoreRows(resultContext,rowBounds)&&!resultSet.isClosed()&&resultSet.next()){
//經過鑑別器鑑別,確定經過鑑別器分析的最終要使用resultMap
ResultMapdiscriminatedResultMap=resolveDiscriminatedResultMap(resultSet,resultMap,null);
//拿到一行記錄,並且將其轉化為一個物件
ObjectrowValue=getRowValue(rsw,discriminatedResultMap,null);
//把這一行記錄轉化出的物件存起來
storeObject(resultHandler,resultContext,rowValue,parentMapping,resultSet);
}
}

DefaultResultSetHandler#getRowValue

  • 解析ResultMap標籤時,會將屬性的TypeHandler確定下來
/**
*將一條記錄轉化為一個物件
*@paramrsw結果集包裝
*@paramresultMap結果對映
*@paramcolumnPrefix列字首
*@return轉化得到的物件
*@throwsSQLException
*/
privateObjectgetRowValue(ResultSetWrapperrsw,ResultMapresultMap,StringcolumnPrefix)throwsSQLException{
finalResultLoaderMaplazyLoader=newResultLoaderMap();
//建立這一行記錄對應的空物件
ObjectrowValue=createResultObject(rsw,resultMap,lazyLoader,columnPrefix);
if(rowValue!=null&&!hasTypeHandlerForResultObject(rsw,resultMap.getType())){
//根據物件得到其MetaObject
finalMetaObjectmetaObject=configuration.newMetaObject(rowValue);
booleanfoundValues=this.useConstructorMappings;
//是否允許自動對映未明示的欄位
if(shouldApplyAutomaticMappings(resultMap,false)){
//自動對映未明示的欄位(resultType),對映時的TypeHandler通過屬性名與set方法引數型別的對映來獲取屬性的型別,並據此獲取對應的TypeHandler
foundValues=applyAutomaticMappings(rsw,resultMap,metaObject,columnPrefix)||foundValues;
}
//按照明示的欄位進行重新對映(resultMap),解析XML時獲取TypeHandler
foundValues=applyPropertyMappings(rsw,resultMap,metaObject,lazyLoader,columnPrefix)||foundValues;
foundValues=lazyLoader.size()>0||foundValues;
rowValue=foundValues||configuration.isReturnInstanceForEmptyRow()?rowValue:null;
}
returnrowValue;
}

以上便是Mybatis中ResultSet結果集處理流程。