二次解析源碼,MyBatis3源碼解析(5)查詢結果處理

 2023-10-12 阅读 28 评论 0

摘要:簡介 上篇中解析了MyBatis3中參數是如何傳遞處理的,本篇接著看看在獲取到查詢結果后,MyBatis3是如何將SQL查詢結果與我們接口函數定義的返回結果對應的 源碼 獲取結果后處理的入口 二次解析源碼。在:MyBatis3源碼解析(3)查詢語句執行中,我們大致知

簡介

上篇中解析了MyBatis3中參數是如何傳遞處理的,本篇接著看看在獲取到查詢結果后,MyBatis3是如何將SQL查詢結果與我們接口函數定義的返回結果對應的

源碼

獲取結果后處理的入口

二次解析源碼。在:MyBatis3源碼解析(3)查詢語句執行中,我們大致知道了查詢結果處理的想代碼位置,如下:

public class PreparedStatementHandler extends BaseStatementHandler {@Overridepublic <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {PreparedStatement ps = (PreparedStatement) statement;ps.execute();// 前面的語句已經執行,處理結果返回return resultSetHandler.handleResultSets(ps);}
}

SQL結果處理

下面是具體的處理邏輯,先獲取結果集和Mapper中定義的返回結果的相關信息,然后對應進行處理

public class DefaultResultSetHandler implements ResultSetHandler {@Overridepublic List<Object> handleResultSets(Statement stmt) throws SQLException {ErrorContext.instance().activity("handling results").object(mappedStatement.getId());final List<Object> multipleResults = new ArrayList<>();int resultSetCount = 0;// 獲取結果集,并用自定義包裝起來ResultSetWrapper rsw = getFirstResultSet(stmt);// 獲取ResultMap對象,一般只有一個,其實就是需要返回的類信息之類的List<ResultMap> resultMaps = mappedStatement.getResultMaps();int resultMapCount = resultMaps.size();validateResultMapsCount(rsw, resultMapCount);while (rsw != null && resultMapCount > resultSetCount) {ResultMap resultMap = resultMaps.get(resultSetCount);// 在這里會循環獲取SQL結果集并進行轉換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);}private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {ResultSet rs = stmt.getResultSet();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)if (stmt.getMoreResults()) {rs = stmt.getResultSet();} else {if (stmt.getUpdateCount() == -1) {// no more results. Must be no resultsetbreak;}}}return rs != null ? new ResultSetWrapper(rs, configuration) : null;}
}

我們一直跟下去,中間步驟不是太關鍵,下發是SQL Result遍歷和結果轉換的相關代碼

public class DefaultResultSetHandler implements ResultSetHandler {private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)throws SQLException {DefaultResultContext<Object> resultContext = new DefaultResultContext<>();ResultSet resultSet = rsw.getResultSet();skipRows(resultSet, rowBounds);// SQLresult遍歷while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);// 將單條SQL結果轉成對象Object rowValue = getRowValue(rsw, discriminatedResultMap, null);// 存儲storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);}}private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {final ResultLoaderMap lazyLoader = new ResultLoaderMap();// 根據返回的類型生成對象Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {final MetaObject metaObject = configuration.newMetaObject(rowValue);boolean foundValues = this.useConstructorMappings;if (shouldApplyAutomaticMappings(resultMap, false)) {foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;}// 結果轉換foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;foundValues = lazyLoader.size() > 0 || foundValues;rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;}return rowValue;}private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)throws SQLException {final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);boolean foundValues = false;// 結果相關的屬性final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();// 遍歷,結果對應對應的值for (ResultMapping propertyMapping : propertyMappings) {// 列名稱String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);if (propertyMapping.getNestedResultMapId() != null) {// the user added a column attribute to a nested result map, ignore itcolumn = null;}if (propertyMapping.isCompositeResult()|| (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))|| propertyMapping.getResultSet() != null) {// 轉換,獲取值Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);// issue #541 make property optionalfinal String property = propertyMapping.getProperty();if (property == null) {continue;} else if (value == DEFERRED) {foundValues = true;continue;}if (value != null) {foundValues = true;}if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {// 更新結果// gcode issue #377, call setter on nulls (value is not 'found')metaObject.setValue(property, value);}}}return foundValues;}private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)throws SQLException {if (propertyMapping.getNestedQueryId() != null) {return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);} else if (propertyMapping.getResultSet() != null) {addPendingChildRelation(rs, metaResultObject, propertyMapping);   // TODO is that OK?return DEFERRED;} else {// 將SQL值轉成對應java對象值,MyBatis3已內容Int Str等轉換器final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);return typeHandler.getResult(rs, column);}}
}

在上面代碼中,我們看到了:

  • 循環遍歷SQL結果:ResultSet
  • 遍歷SQL列,轉成Java類型

MyBatis中已經內置很多的類型轉換器,也可以自己自定義,比如內容Long如下:

public class LongTypeHandler extends BaseTypeHandler<Long> {@Overridepublic Long getNullableResult(ResultSet rs, String columnName)throws SQLException {long result = rs.getLong(columnName);return result == 0 && rs.wasNull() ? null : result;}
}

總結

本篇文章中探索的MyBatis中如何將查詢結果轉換成我們想要的Java對象

  • SQL執行
  • 遍歷ResultSet
  • 遍歷數據庫Column,根據列名稱,獲取對應的值,轉成Java對象

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/2/135533.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息