新聞中心
resultMap ?元素是 Mybatis 中最重要最強大的元素。它可以讓你從 90% 的 ?JDBC ResultSets? 數(shù)據(jù)提取代碼中解放出來,并在一些情形下允許你進行一些 ?JDBC ?不支持的操作。實際上,在為一些比如連接的復(fù)雜語句編寫映射代碼的時候,一份 ?resultMap ?能夠代替實現(xiàn)同等功能的數(shù)千行代碼。?ResultMap ?的設(shè)計思想是,對簡單的語句做到零配置,對于復(fù)雜一點的語句,只需要描述語句之間的關(guān)系就行了。

創(chuàng)新互聯(lián)服務(wù)項目包括扎賚諾爾網(wǎng)站建設(shè)、扎賚諾爾網(wǎng)站制作、扎賚諾爾網(wǎng)頁制作以及扎賚諾爾網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,扎賚諾爾網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到扎賚諾爾省份的部分城市,未來相信會繼續(xù)擴大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
之前你已經(jīng)見過簡單映射語句的示例,它們沒有顯式指定 ?resultMap?。比如:
上述語句只是簡單地將所有的列映射到 ?HashMap ?的鍵上,這由 ?resultType ?屬性指定。雖然在大部分情況下都夠用,但是 ?HashMap ?并不是一個很好的領(lǐng)域模型。你的程序更可能會使用 ?JavaBean ?或 ?POJO?(?Plain Old Java Objects?,普通老式 Java 對象)作為領(lǐng)域模型。MyBatis 對兩者都提供了支持。看看下面這個 ?JavaBean?:
package com.someapp.model;
public class User {
private int id;
private String username;
private String hashedPassword;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getHashedPassword() {
return hashedPassword;
}
public void setHashedPassword(String hashedPassword) {
this.hashedPassword = hashedPassword;
}
}
基于 ?JavaBean ?的規(guī)范,上面這個類有 3 個屬性:?id?,?username ?和 ?hashedPassword?。這些屬性會對應(yīng)到 ?select ?語句中的列名。
這樣的一個 ?JavaBean ?可以被映射到 ?ResultSet?,就像映射到 ?HashMap ?一樣簡單。
類型別名是你的好幫手。使用它們,你就可以不用輸入類的全限定名了。比如:
在這些情況下,MyBatis 會在幕后自動創(chuàng)建一個 ?ResultMap?,再根據(jù)屬性名來映射列到 ?JavaBean ?的屬性上。如果列名和屬性名不能匹配上,可以在 ?SELECT ?語句中設(shè)置列別名(這是一個基本的 SQL 特性)來完成匹配。比如:
在學習了上面的知識后,你會發(fā)現(xiàn)上面的例子沒有一個需要顯式配置 ?ResultMap?,這就是 ?ResultMap ?的優(yōu)秀之處——你完全可以不用顯式地配置它們。 雖然上面的例子不用顯式配置 ?ResultMap?。 但為了講解,我們來看看如果在剛剛的示例中,顯式使用外部的 ?resultMap ?會怎樣,這也是解決列名不匹配的另外一種方式。
然后在引用它的語句中設(shè)置 ?resultMap ?屬性就行了(注意我們?nèi)サ袅?nbsp;?resultType ?屬性)。比如:
高級結(jié)果映射
MyBatis 創(chuàng)建時的一個思想是:數(shù)據(jù)庫不可能永遠是你所想或所需的那個樣子。 我們希望每個數(shù)據(jù)庫都具備良好的第三范式或 ?BCNF ?范式,可惜它們并不都是那樣。 如果能有一種數(shù)據(jù)庫映射模式,完美適配所有的應(yīng)用程序,那就太好了,但可惜也沒有。 而 ?ResultMap ?就是 MyBatis 對這個問題的答案。
比如,我們?nèi)绾斡成湎旅孢@個語句?
你可能想把它映射到一個智能的對象模型,這個對象表示了一篇博客,它由某位作者所寫,有很多的博文,每篇博文有零或多條的評論和標簽。 我們先來看看下面這個完整的例子,它是一個非常復(fù)雜的結(jié)果映射(假設(shè)作者,博客,博文,評論和標簽都是類型別名)。 不用緊張,我們會一步一步地來說明。雖然它看起來令人望而生畏,但其實非常簡單。
??resultMap ??元素有很多子元素和一個值得深入探討的結(jié)構(gòu)。 下面是?resultMap ?元素的概念視圖。
結(jié)果映射(resultMap)
- ?constructor ?- 用于在實例化類時,注入結(jié)果到構(gòu)造方法中
- ?idArg ?- ID 參數(shù);標記出作為 ID 的結(jié)果可以幫助提高整體性能?arg ?- 將被注入到構(gòu)造方法的一個普通結(jié)果
- ?id ?– 一個 ID 結(jié)果;標記出作為 ID 的結(jié)果可以幫助提高整體性能
- ?result ?– 注入到字段或 ?JavaBean ?屬性的普通結(jié)果
- ?association ?– 一個復(fù)雜類型的關(guān)聯(lián);許多結(jié)果將包裝成這種類型
- 嵌套結(jié)果映射 – 關(guān)聯(lián)可以是 ?resultMap ?元素,或是對其它結(jié)果映射的引用
- ?collection ?– 一個復(fù)雜類型的集合
- 嵌套結(jié)果映射 – 集合可以是 ?resultMap ?元素,或是對其它結(jié)果映射的引用
- ?discriminator ?– 使用結(jié)果值來決定使用哪個 ?resultMap?
- ?case ?– 基于某些值的結(jié)果映射嵌套結(jié)果映射 – ?case ?也是一個結(jié)果映射,因此具有相同的結(jié)構(gòu)和元素;或者引用其它的結(jié)果映射
| 屬性 | 描述 |
|---|---|
id | 當前命名空間中的一個唯一標識,用于標識一個結(jié)果映射。 |
type | 類的完全限定名, 或者一個類型別名(關(guān)于內(nèi)置的類型別名,可以參考上面的表格)。 |
autoMapping | 如果設(shè)置這個屬性,MyBatis 將會為本結(jié)果映射開啟或者關(guān)閉自動映射。 這個屬性會覆蓋全局的屬性 autoMappingBehavior。默認值:未設(shè)置(unset)。 |
最好逐步建立結(jié)果映射。單元測試可以在這個過程中起到很大幫助。 如果你嘗試一次性創(chuàng)建像上面示例那么巨大的結(jié)果映射,不僅容易出錯,難度也會直線上升。 所以,從最簡單的形態(tài)開始,逐步迭代。而且別忘了單元測試! 有時候,框架的行為像是一個黑盒子(無論是否開源)。因此,為了確保實現(xiàn)的行為與你的期望相一致,最好編寫單元測試。 并且單元測試在提交 bug 時也能起到很大的作用。
下一部分將詳細說明每個元素。
id & result
這些元素是結(jié)果映射的基礎(chǔ)。id 和 result 元素都將一個列的值映射到一個簡單數(shù)據(jù)類型(String, int, double, Date 等)的屬性或字段。
這兩者之間的唯一不同是,id 元素對應(yīng)的屬性會被標記為對象的標識符,在比較對象實例時使用。 這樣可以提高整體的性能,尤其是進行緩存和嵌套結(jié)果映射(也就是連接映射)的時候。
兩個元素都有一些屬性:
| 屬性 | 描述 |
|---|---|
property | 映射到列結(jié)果的字段或?qū)傩?。如?JavaBean 有這個名字的屬性(property),會先使用該屬性。否則 MyBatis 將會尋找給定名稱的字段(field)。 無論是哪一種情形,你都可以使用常見的點式分隔形式進行復(fù)雜屬性導航。 比如,你可以這樣映射一些簡單的東西:“username”,或者映射到一些復(fù)雜的東西上:“address.street.number”。 |
column | 數(shù)據(jù)庫中的列名,或者是列的別名。一般情況下,這和傳遞給 resultSet.getString(columnName) 方法的參數(shù)一樣。 |
javaType | 一個 Java 類的全限定名,或一個類型別名(關(guān)于內(nèi)置的類型別名,可以參考上面的表格)。 如果你映射到一個 JavaBean,MyBatis 通??梢酝茢囝愋汀H欢?,如果你映射到的是 HashMap,那么你應(yīng)該明確地指定 javaType 來保證行為與期望的相一致。 |
jdbcType | JDBC 類型,所支持的 JDBC 類型參見這個表格之后的“支持的 JDBC 類型”。 只需要在可能執(zhí)行插入、更新和刪除的且允許空值的列上指定 JDBC 類型。這是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 編程,你需要對可以為空值的列指定這個類型。 |
typeHandler | 我們在前面討論過默認的類型處理器。使用這個屬性,你可以覆蓋默認的類型處理器。 這個屬性值是一個類型處理器實現(xiàn)類的全限定名,或者是類型別名。 |
支持的 JDBC 類型
為了以后可能的使用場景,MyBatis 通過內(nèi)置的 ?jdbcType ?枚舉類型支持下面的 ?JDBC ?類型。
BIT | FLOAT | CHAR | TIMESTAMP | OTHER | UNDEFINED |
TINYINT | REAL | VARCHAR | BINARY | BLOB | NVARCHAR |
SMALLINT | DOUBLE | LONGVARCHAR | VARBINARY | CLOB | NCHAR |
INTEGER | NUMERIC | DATE | LONGVARBINARY | BOOLEAN | NCLOB |
BIGINT | DECIMAL | TIME | NULL | CURSOR | ARRAY |
構(gòu)造方法
通過修改對象屬性的方式,可以滿足大多數(shù)的數(shù)據(jù)傳輸對象(?Data Transfer Object?, ?DTO?)以及絕大部分領(lǐng)域模型的要求。但有些情況下你想使用不可變類。 一般來說,很少改變或基本不變的包含引用或數(shù)據(jù)的表,很適合使用不可變類。 構(gòu)造方法注入允許你在初始化時為類設(shè)置屬性的值,而不用暴露出公有方法。MyBatis 也支持私有屬性和私有 ?JavaBean ?屬性來完成注入,但有一些人更青睞于通過構(gòu)造方法進行注入。 ?constructor ?元素就是為此而生的。
看看下面這個構(gòu)造方法:
public class User {
//...
public User(Integer id, String username, int age) {
//...
}
//...
}為了將結(jié)果注入構(gòu)造方法,MyBatis 需要通過某種方式定位相應(yīng)的構(gòu)造方法。 在下面的例子中,MyBatis 搜索一個聲明了三個形參的構(gòu)造方法,參數(shù)類型以 ?java.lang.Integer?, ?java.lang.String? 和 ?int ?的順序給出。
當你在處理一個帶有多個形參的構(gòu)造方法時,很容易搞亂 ?arg ?元素的順序。 從版本 3.4.3 開始,可以在指定參數(shù)名稱的前提下,以任意順序編寫 ?arg ?元素。 為了通過名稱來引用構(gòu)造方法參數(shù),你可以添加 ?@Param? 注解,或者使用 '?-parameters?' 編譯選項并啟用 ?useActualParamName ?選項(默認開啟)來編譯項目。下面是一個等價的例子,盡管函數(shù)簽名中第二和第三個形參的順序與 ?constructor ?元素中參數(shù)聲明的順序不匹配。
如果存在名稱和類型相同的屬性,那么可以省略 ?javaType ?。
剩余的屬性和規(guī)則和普通的 ?id ?和 ?result ?元素是一樣的。
| 屬性 | 描述 |
|---|---|
column | 數(shù)據(jù)庫中的列名,或者是列的別名。一般情況下,這和傳遞給 resultSet.getString(columnName) 方法的參數(shù)一樣。 |
javaType | 一個 Java 類的完全限定名,或一個類型別名(關(guān)于內(nèi)置的類型別名,可以參考上面的表格)。 如果你映射到一個 JavaBean,MyBatis 通??梢酝茢囝愋汀H欢?,如果你映射到的是 HashMap,那么你應(yīng)該明確地指定 javaType 來保證行為與期望的相一致。 |
jdbcType | JDBC 類型,所支持的 JDBC 類型參見這個表格之前的“支持的 JDBC 類型”。 只需要在可能執(zhí)行插入、更新和刪除的且允許空值的列上指定 JDBC 類型。這是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 編程,你需要對可能存在空值的列指定這個類型。 |
typeHandler | 我們在前面討論過默認的類型處理器。使用這個屬性,你可以覆蓋默認的類型處理器。 這個屬性值是一個類型處理器實現(xiàn)類的完全限定名,或者是類型別名。 |
select | 用于加載復(fù)雜類型屬性的映射語句的 ID,它會從 column 屬性中指定的列檢索數(shù)據(jù),作為參數(shù)傳遞給此 select 語句。具體請參考關(guān)聯(lián)元素。 |
resultMap | 結(jié)果映射的 ID,可以將嵌套的結(jié)果集映射到一個合適的對象樹中。 它可以作為使用額外 select 語句的替代方案。它可以將多表連接操作的結(jié)果映射成一個單一的 ResultSet。這樣的 ResultSet 將會將包含重復(fù)或部分數(shù)據(jù)重復(fù)的結(jié)果集。為了將結(jié)果集正確地映射到嵌套的對象樹中,MyBatis 允許你 “串聯(lián)”結(jié)果映射,以便解決嵌套結(jié)果集的問題。想了解更多內(nèi)容,請參考下面的關(guān)聯(lián)元素。 |
name | 構(gòu)造方法形參的名字。從 3.4.3 版本開始,通過指定具體的參數(shù)名,你可以以任意順序?qū)懭?arg 元素。參看上面的解釋。 |
新聞名稱:創(chuàng)新互聯(lián)MyBatis教程:MyBatis 3 結(jié)果映射-基本方法
轉(zhuǎn)載注明:http://www.dlmjj.cn/article/dpeppjo.html


咨詢
建站咨詢
