Mybatis原始碼之ResultSet結果集處理
阿新 • • 發佈:2021-09-06
時序圖
詳細步驟
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結果集處理流程。