MyBatis最后一步一定是處理相關的結果——把數據映射成對應的模型對象。事實上在筆者看來如果讀者們了解了mybatis如何去執行數據庫,又是如何處理數據結果。那么就了解了mybatis的主要路線。因為不管是什么樣子的ORM最終都是要執行和處理結果的。而mybatis的亮點筆者也講了——管理sql語句。所以相對而言,處理結果就顯得十分的次要。但是筆者還是希望能在這里停留一下,研究他是如何處理結果。
mybatis處理結果的代碼都在DefaultResultSetHandler類里面。很抱歉的是筆者去掉了程序是如何執行到DefaultResultSetHandler類的。這里面還是希望讀者們自行的去跟蹤一下。DefaultResultSetHandler類的handleResultSets方法便是筆者切入的代碼。事實上當代碼執行到handleResultSets方法的時候,已經執行了數據庫。這在PreparedStatementHandler類里面就體現出來了。如下
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; ps.execute(); return resultSetHandler.<E> handleResultSets(ps); }
用過mybatis的人都知道resultMap節點的作用。select節點的resultMap屬性就是用來指點使用哪一個resultMap節點。而返回的結果也是用這一個節點來設置的。如下
<select id="SelectProducts" resultMap="result" > select * from Products where #{0} > ProductID and ProductName like #{1} </select> <resultMap type="com.aomi.vo.Product" id="result" autoMapping="true"> </resultMap>
所以我可以設想一下。當我們拿到了數據的時候,希望數據變成我們指定的對象模型。那么我們就必須知道是什么類型。一般來講只要知道了什么類型就可以完成基本的映射條件。那么還會有可能出現一種希望自己去設計映射的字段和實例化對象。所以mybatis在這一方面也算是讓筆者很喜歡。細詳你可以查看一下官方的網站——XML映射文件。
在映射的過程中,往往我們都需要知道表的字段。所以在DefaultResultSetHandler類的handleResultSets方法里面一開始就獲得了關於表的信息。表的信息都存放在ResultSetWrapper類里面。后面便就是根據這些信息來處理每一行的數據。我們還是看一下源碼吧。
1 public List<Object> handleResultSets(Statement stmt) throws SQLException { 2 ErrorContext.instance().activity("handling results").object(mappedStatement.getId()); 3 4 final List<Object> multipleResults = new ArrayList<Object>(); 5 6 int resultSetCount = 0; 7 ResultSetWrapper rsw = getFirstResultSet(stmt); 8 9 List<ResultMap> resultMaps = mappedStatement.getResultMaps(); 10 int resultMapCount = resultMaps.size(); 11 validateResultMapsCount(rsw, resultMapCount); 12 while (rsw != null && resultMapCount > resultSetCount) { 13 ResultMap resultMap = resultMaps.get(resultSetCount); 14 handleResultSet(rsw, resultMap, multipleResults, null); 15 rsw = getNextResultSet(stmt); 16 cleanUpAfterHandlingResultSet(); 17 resultSetCount++; 18 } 19 20 String[] resultSets = mappedStatement.getResultSets(); 21 if (resultSets != null) { 22 while (rsw != null && resultSetCount < resultSets.length) { 23 ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]); 24 if (parentMapping != null) { 25 String nestedResultMapId = parentMapping.getNestedResultMapId(); 26 ResultMap resultMap = configuration.getResultMap(nestedResultMapId); 27 handleResultSet(rsw, resultMap, null, parentMapping); 28 } 29 rsw = getNextResultSet(stmt); 30 cleanUpAfterHandlingResultSet(); 31 resultSetCount++; 32 } 33 } 34 35 return collapseSingleResultList(multipleResults); 36 }
筆者標出切入需要的倆個代碼段。一個就是獲得表信息的,另一個就是用於處理每一行數據的。事實上面的multipleResults變量就能說明一個問題——可能實現多個select句語的執行。所以相對的reusltMap也變成了集合類型。在XML上面就是用逗號隔開的。筆者沒有做過類似這種方式的代碼。筆者也是從源碼中看來的。他在MapperBuilderAssistant類的getStatementResultMaps方法里面。如下。
String[] resultMapNames = resultMap.split(",");
具體情況讀者們可以自己去實驗一下。
在筆者看來想要理解這一部分的關鍵點還在是getRowValue方法這邊。這里面就是我們所說的處理結果。根據reusltMap節點的信息判斷出是要自己根據類型生成對象。還是要通過reusltMap節點配置信息來生成對象。然后直行獲值和設值。如下。
1 private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException { 2 final ResultLoaderMap lazyLoader = new ResultLoaderMap(); 3 Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null); 4 if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) { 5 final MetaObject metaObject = configuration.newMetaObject(resultObject); 6 boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty(); 7 if (shouldApplyAutomaticMappings(resultMap, false)) { 8 foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues; 9 } 10 foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues; 11 foundValues = lazyLoader.size() > 0 || foundValues; 12 resultObject = foundValues ? resultObject : null; 13 return resultObject; 14 } 15 return resultObject; 16 }
1.createResultObject方法:根據類型和配置信息生成對象。
2.applyAutomaticMappings方法:判斷是否是autoMapping="true",如果是就是自動映射賦值。
3.applyPropertyMappings方法:根據配置信息賦值。
接下來,就是各位讀者們根據自己的需要進行進一步的研究了。如果想知道是如何生成對象就是去看createResultObject方法。賦值的話就去看applyAutomaticMappings方法和applyPropertyMappings方法。