日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入了解MyBatis返回值

發布時間:2025/3/21 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入了解MyBatis返回值 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

深入了解MyBatis返回值

想了解返回值,我們需要了解resultType,resultMap以及接口方法中定義的返回值。

我們先看resultType和resultMap

resultType和resultMap

大家應該都知道在MyBatis的<select>標簽中有兩種設置返回值的方式,分別是resultMap和resultType。

處理resultMap和resultType的代碼如下:

private void setStatementResultMap(String resultMap,Class<?> resultType,ResultSetType resultSetType,MappedStatement.Builder statementBuilder) {resultMap = applyCurrentNamespace(resultMap, true);List<ResultMap> resultMaps = new ArrayList<ResultMap>();if (resultMap != null) {String[] resultMapNames = resultMap.split(",");for (String resultMapName : resultMapNames) {try {resultMaps.add(configuration.getResultMap(resultMapName.trim()));} catch (IllegalArgumentException e) {throw new IncompleteElementException("Could not find result map " + resultMapName, e);}}} else if (resultType != null) {ResultMap.Builder inlineResultMapBuilder = new ResultMap.Builder(configuration,statementBuilder.id() + "-Inline",resultType,new ArrayList<ResultMapping>(),null);resultMaps.add(inlineResultMapBuilder.build());}statementBuilder.resultMaps(resultMaps);statementBuilder.resultSetType(resultSetType); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

可以看到這里會優先處理resultMap,但是也使用了resultType。

接下來看MyBatis獲取數據后,如果處理一行結果(以簡單數據為例,不考慮嵌套情況):

private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {final ResultLoaderMap lazyLoader = new ResultLoaderMap();Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null);if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {final MetaObject metaObject = configuration.newMetaObject(resultObject);boolean foundValues = resultMap.getConstructorResultMappings().size() > 0;if (shouldApplyAutomaticMappings(resultMap, !AutoMappingBehavior.NONE.equals(configuration.getAutoMappingBehavior()))) {foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;}foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;foundValues = lazyLoader.size() > 0 || foundValues;resultObject = foundValues ? resultObject : null;return resultObject;}return resultObject; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

上面這段代碼中重要的代碼如下:

if (shouldApplyAutomaticMappings(resultMap, !AutoMappingBehavior.NONE.equals(configuration.getAutoMappingBehavior()))) {foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues; } foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

if中判斷的是當前是否支持自動映射(可以配置),這一點很重要,如果不支持,那么沒法使用resultType方式,必須用resultMap方式,如果支持,resultType方式和resultMap方式可以同時使用

這里的基本邏輯是先對沒有resultMap的屬性自動映射賦值,通過applyAutomaticMappings實現。

如果對象有resultMap,那么還會進行applyPropertyMappings方法。

也就是先處理resultType中自動映射的字段,在處理resultMap中的配置的字段,兩者可以同時使用!

下面按照順序分別說兩種方式。

resultType方式

如果支持自動映射,那么會執行applyAutomaticMappings,這里面有metaObject參數。

final MetaObject metaObject = configuration.newMetaObject(resultObject);
  • 1
  • 1

我們看看創建metaObject最關鍵的一個地方,在Reflector類中:

for (String propName : readablePropertyNames) {caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName); }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

這里將實體中的屬性名,做了一個映射,是大寫的對應實際的屬性名。例如ID:id。

在applyAutomaticMappings中的第一行,首先獲取沒有映射的列名:

final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
  • 1
  • 1

獲取列名的時候:

for (String columnName : columnNames) {final String upperColumnName = columnName.toUpperCase(Locale.ENGLISH);if (mappedColumns.contains(upperColumnName)) {mappedColumnNames.add(upperColumnName);} else {unmappedColumnNames.add(columnName);} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

注意這里將列名轉換為大寫形式,同時保存了mappedColumnNames映射的列和unmappedColumnNames未映射的列。

因為不管是屬性名還是查詢列都是大寫的,所以只要列名和屬性名大寫一致,就會匹配上。

因此我們在寫sql的時候,不需要對查詢列的大小寫進行轉換,自動匹配是不區分大小寫的。

resultMap方式

這種方式也很簡單,上面提到了mappedColumnNames,在判斷是否為映射列的時候,使用mappedColumns.contains(upperColumnName)進行判斷,mappedColumns是我們配置的映射的列,那是不是我們配置的時候必須大寫呢?

實際上不用,這里也不區分大小寫,在<result column="xxx" ../>的column也不區分大小寫,看下面的代碼:

for (ResultMapping compositeResultMapping : resultMapping.getComposites()) {final String compositeColumn = compositeResultMapping.getColumn();if (compositeColumn != null) {resultMap.mappedColumns.add(compositeColumn.toUpperCase(Locale.ENGLISH));} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

這里也轉換為了大寫。

到這里關于resultTypt和resultMap就結束了,但是有一個簡單的問題,很多人不懂,是什么?看下個標題。

MyBatis接口返回值

接口返回值通常是一個結果,或者是List和數組。

MyBatis如何知道我想要返回一個結果還是多個結果?

在MapperMethod中的部分代碼如下:

if (method.returnsVoid() && method.hasResultHandler()) {executeWithResultHandler(sqlSession, args);result = null; } else if (method.returnsMany()) {result = executeForMany(sqlSession, args); } else if (method.returnsMap()) {result = executeForMap(sqlSession, args); } else {Object param = method.convertArgsToSqlCommandParam(args);result = sqlSession.selectOne(command.getName(), param); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

可以看到查詢結果有4中情況,void,list(和array),map,one。

這里重要就是if的判斷條件,這種判斷條件計算方法:

this.returnType = method.getReturnType(); this.returnsVoid = void.class.equals(this.returnType); this.returnsMany = (configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray());
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

可以看到,這些條件完全就是通過方法的返回值決定的。所以如果你寫的返回值是數組或者集合,返回的結果就是多個。

如果返回值本身有多個,但是返回值寫了一個POJO,不是集合或者數組時會怎樣?

答案是會報錯TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size())。

不管是返回一個結果還是多個結果,MyBatis都是安裝多個結果進行查詢,selectOne是查詢一個,selectList是查詢多個,我們看看selectOne代碼:

public <T> T selectOne(String statement, Object parameter) {List<T> list = this.<T>selectList(statement, parameter);if (list.size() == 1) {return list.get(0);} else if (list.size() > 1) {throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());} else {return null;} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

注意看:

List<T> list = this.<T>selectList(statement, parameter);
  • 1
  • 1

實際上,不管查詢一個還是多個結果,MyBatis都是先按多個結果進行查詢。拿到list結果后在判斷。

如果是查詢一個結果的情況,那么list最多只能有一個返回值。通過上面代碼的if else if esle可以很明白的理解。

resultTyp,resultMap和返回值多少有關系嗎?

沒有任何關系。

通過前面resultType和resultMap的內容,我們應該知道,這個屬性是配置JDBC查詢結果如何映射到一個對象上的。

不管返回值是什么或者是幾個,都是按照resultType和resultMap生成返回結果。

返回結果的類型由resultType和resultMap決定。

返回結果的類型

返回結果的類型由resultType和resultMap決定,是不是很詫異???

實際上就是這種情況。。

舉個例子,有個實體Country和Country2。

接口中List<Country> selectAll(),xml中的<select id="selectAll" resultType="Country2">.

當你通過接口調用的時候,返回值是什么?你以為自己的List中的對象類型是Country,但他們實際上都是Country2

如果接口方法為Country selectById(Integer id),xml中為<select id="selectById" resultType="Country2">,由于類型不一致,查詢的時候才會報錯:Java.lang.ClassCastException: xx.Country2 cannot be cast to xx.Country

為什么會這樣呢?

這是因為接口調用方式是對命名空間方式調用的封裝。

當你通過命名空間方式調用的時候,返回結果的類型是什么?

就是由resultType和resultMap決定的類型,這很容易理解。但是換成接口就覺得不一樣了。

這是由于接口方法方式多了返回值,所以我們會認為返回的一定是這個類型。實際上是錯的。

特殊情況

當使用純注解方式時,接口的返回值類型可以起到作用,如果沒有使用@ResultType注解指定返回值類型,那么就會使用這里寫的返回值類型作為resultType。


from:?http://blog.csdn.net/isea533/article/details/46442067

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的深入了解MyBatis返回值的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。