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

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


咨詢
建站咨詢
