當前位置:
首頁 > 最新 > Mybatis 處理列名、欄位名映射–AS用法&ResultMap

Mybatis 處理列名、欄位名映射–AS用法&ResultMap

接上次的博文,看看第二種和第三種方案,因為第二種方案比較簡單,和第三種方案放在一起看了。

前言

考慮到在Select時使用AS和方案一其實沒什麼差別,在介紹ResultMap之前,順便帶過一下。

方案二-Select …. AS

當我們的資料庫列名和對象欄位之間不是駝峰式命名的關係,我們可以在Select時使用AS,使得列名和對象名匹配上。

映射文件中是本次會執行的sql,我們會查出id,city_id,city_name,city_en_name。 按照開啟的駝峰式命名開關,我們會對應到對象的id,cityId,cityName,cityEnName欄位。

select id,city_id,city_name

不過在這次,我們對PO做了小小的改動,把cityEnName改成了cityEnglishName。

由於找不到匹配的列,cityEnlishName肯定沒法被反射賦值,要為Null了。

CityPO

解決辦法: 在Select欄位的時候使用AS,下面是改動後的映射文件。

select id, city_id, city_name

改動後執行得到的結果如下。

那麼我們來看看它是如何生效的,主要的代碼在哪裡。在昨天我們第一個介紹的函數handleRowValues中傳入了參數rsw,它是對ResultSet的一個包裝,在這個包裝里,完成了具體使用哪個名字作為資料庫的列名。

final ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration); handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);

在這個構造函數當中,我們會獲取資料庫的列名,AS為什麼可以生效,具體就在下面這段代碼。

在添加列名時,會從配置中獲取是否使用類標籤,isUseColumnLabel,默認為true。根據Javadoc,這個ColumnLabel就是AS後的那個名字,如果沒有AS的話,就是獲取的原生的欄位名。

the value returned from * getColumnLabel will be the same as the value returned by the * getColumnName method. * * @param column the first column is 1, the second is 2, ... * @return the suggested column title * @exception SQLException if a database access error occurs */ String getColumnLabel(int column) throws SQLException;

後面的過程就和昨天講的方案一一模一樣了,不再贅述。

方案三-ResultMap

resultMap 元素是 MyBatis 中最重要最強大的元素。它就是讓你遠離 90%的需要從結果 集中取出數據的 JDBC 代碼的那個東西, 而且在一些情形下允許你做一些 JDBC 不支持的事 情。 事實上, 編寫相似於對複雜語句聯合映射這些等同的代碼, 也許可以跨過上千行的代碼。 ResultMap 的設計就是簡單語句不需要明確的結果映射,而很多複雜語句確實需要描述它們 的關係。

ResultMap是Mybatis中可以完成複雜語句映射的東西,但在我們的日常開發中,我們往往是一個XML對應JavaBeans 或 POJOs(Plain Old Java Objects,普通 Java 對象),並沒有特別複雜的應用,下面也是基於日常的使用,看看簡單的ResultMap在源碼層面是如何展現的。

在resultMap的子元素result對應了result和對象欄位之間的映射,並通過id標示,你在Select語句中指定需要使用的resultMap即可。

源碼層面的話,依舊在DefaultResultSetHandler的handleResultSets中處理返回集合。

List resultMaps = mappedStatement.getResultMaps();

在這次的ResultMap中,相比之前方案,其屬性更加的豐富起來。將之前寫的Result的信息保存在了resultMappings,idResultMappings等中,以備後續使用。

後續的函數走向和方案一二一致,在創建自動映射的時候出現了不同。

private List createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {

在這個函數中,會獲取沒有映射過的列名。

final List unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);

之後會根據resultMap查看是否有未映射的欄位。

loadMappedAndUnmappedColumnNames(resultMap, columnPrefix);List mappedColumnNames = new ArrayList(); List unmappedColumnNames = new ArrayList(); final String upperColumnPrefix = columnPrefix == null ,根據之前的圖,定義了ResultMap後,會記錄這些已經配置映射的欄位。 final Set mappedColumns = prependPrefixes(resultMap.getMappedColumns(), upperColumnPrefix); for (String columnName : columnNames) { // 遍歷列名,如果在已映射的配置中,那麼就加入已經映射的列名數據, final String upperColumnName = columnName.toUpperCase(Locale.ENGLISH); if (mappedColumns.contains(upperColumnName)) { mappedColumnNames.add(upperColumnName); } else { unmappedColumnNames.add(columnName); } } // 生成未映射和已映射的Map mappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), mappedColumnNames); unMappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), unmappedColumnNames);

如果有沒配置在ResultMap中,且Select出來的,那麼之後也會按照之前方案一那樣,繼續往下走,去對象中尋找映射關係。

由於沒有未映射的欄位,使用自動映射的結果是false。

foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;

之後繼續往下走,使用applyPropertyMappings來創建對象。使用了PropertyMapping。裡面包含了欄位名,列名,欄位的類型和對應的處理器。

遍歷整個Mappings。

Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);

函數里主要的就是獲取這個欄位對應的類型處理器,防止類型轉換失敗,這一部分下次會專門看一下。

final TypeHandler typeHandler = propertyMapping.getTypeHandler(); final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix); return typeHandler.getResult(rs, column);

TypeHandler就是一個介面,主要完成的工作就是從Result根據列名,獲取相應類型的值,為下一步反射賦值做準備。至於它是怎麼決定為什麼用這個類型的TypeHandler下次再看。最後就是給對應欄位賦值。

metaObject.setValue(property, value);

最後就完成了整個類的賦值。

總結

大致上,Mybatis完成映射主要是兩種方式。

1. 只根據列名,利用自動映射,根據反射類的信息,得到列名和欄位之間的關係,使用對應的TypeHandler,完成欄位的賦值。

2. 使用ResultMap預先定義好映射關係,也是最後根據TypeHandler和反射,完成欄位的賦值。

我個人感覺就簡單的用法來說,兩者都可以,在一次會話中,Configuration中的ResultMap關係建立好,在每一次查詢的時候就不用再去重新建立了,直接用就行。而自動映射的話,執行過一次後,也會在會話中建立自動映射的緩存。所以沒什麼差別。但如果複雜的映射的話,就非ResultMap莫屬啦。具體可以參考Mybatis文檔關於映射的章節,因為目前用不到比較複雜的映射, 不做深究了。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 推酷 的精彩文章:

如何做 Go 的性能優化?
Xcode代碼全黑的另一種解決辦法
微軟推出了一款 App 可以幫你讀出全世界
PSAttack:一個包含所有的滲透測試用例的攻擊型Powershell腳本框架
一個靈活的AssetBundle打包工具

TAG:推酷 |

您可能感興趣

Hibernate 映射枚舉Enum 類型的屬性
mybatis與spring整合:Dao層映射配置
Occipital推出MR創作工具Bridge Engine,實現密實3D映射
零示例學習中的映射域遷移 (projection domain shift) 問題
kali Linux信息收集-網路映射工具Nmap
將2D圖像人物實時映射3D模型,Facebook開源DensePose技術
實現mybatis框架SQL映射文件SQL片段
MyBatis框架之SQL映射和動態SQL
Linux內存映射mmap原理分析
Magic Leap系統為多人MR共享增加映射融合特性
神作Revive再更新,Index手柄可良好映射Rift按鍵
BigOne將支持EOS主網映射
三星對Galaxy S8/S9的Bixby鍵開放重新映射功能
ZB.com幫你安全完成EOS映射
使用IDAPython自動映射二進位文件替換默認函數名
Facebook最新開源,普通RGB相機即可實時映射3D模型
ARKit 1.5 demo展示了iOS 11.3中的垂直平面映射升級
深入淺出MyBatis:「映射器」全了解
linux下簡單好用的工具rinetd,實現埠映射/轉發/重定向
哪種特徵分析法適合你的任務?Ian Goodfellow提出顯著性映射的可用性測試