resultMap 元素是 MyBatis 中最重要最強大的元素。它就是讓你遠離 90%的需要從結果 集中取出數據的 JDBC 代碼的那個東西, 而且在一些情形下允許你做一些 JDBC 不支持的事 情。 事實上, 編寫相似於對複雜語句聯合映射這些等同的代碼, 也許可以跨過上千行的代碼。
ResultMap 的設計就是簡單語句不需要明確的結果映射,而很多複雜語句確實需要描述它們 的關係。
你已經看到簡單映射語句的示例了,但沒有明確的 resultMap。比如:
<select id="selectUsers" resultType="map">
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
這樣一個語句簡單作用於所有列被自動映射到 HashMap 的鍵上,這由 resultType 屬性 指定。這在很多情況下是有用的,但是 HashMap 不能很好描述一個領域模型。那樣你的應 用程序將會使用 JavaBeans 或 POJOs(Plain Old Java Objects,普通 Java 對象)來作爲領域 模型。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 的規範,上面這個類有 3 個屬性:id,username 和 hashedPassword。這些 在 select 語句中會精確匹配到列名。
這樣的一個 JavaBean 可以被映射到結果集,就像映射到 HashMap 一樣簡單。
<select id="selectUsers" resultType="com.someapp.model.User">
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
要記住類型別名是你的夥伴。使用它們你可以不用輸入類的全路徑。比如:
<!-- In mybatis-config.xml file -->
<typeAlias type="com.someapp.model.User" alias="User"/>
<!-- In SQL Mapping XML file -->
<select id="selectUsers" resultType="User">
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
這些情況下,MyBatis 會在幕後自動創建一個 ResultMap,基於屬性名來映射列到 JavaBean 的屬性上。如果列名沒有精確匹配,你可以在列名上使用 select 字句的別名(一個 基本的 SQL 特性)來匹配標籤。比如:
<select id="selectUsers" resultType="User">
select
user_id as "id",
user_name as "userName",
hashed_password as "hashedPassword"
from some_table
where id = #{id}
</select>
ResultMap 最優秀的地方你已經瞭解了很多了,但是你還沒有真正的看到一個。這些簡 單的示例不需要比你看到的更多東西。 只是出於示例的原因, 讓我們來看看最後一個示例中 外部的 resultMap 是什麼樣子的,這也是解決列名不匹配的另外一種方式。
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>
引用它的語句使用 resultMap 屬性就行了(注意我們去掉了 resultType 屬性)。比如:
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>
如果世界總是這麼簡單就好了。
高級結果映射
MyBatis 創建的一個想法:數據庫不用永遠是你想要的或需要它們是什麼樣的。而我們 最喜歡的數據庫最好是第三範式或 BCNF 模式,但它們有時不是。如果可能有一個單獨的 數據庫映射,所有應用程序都可以使用它,這是非常好的,但有時也不是。結果映射就是 MyBatis 提供處理這個問題的答案。
比如,我們如何映射下面這個語句?
<!-- Very Complex Statement -->
<select id="selectBlogDetails" resultMap="detailedBlogResultMap">
select
B.id as blog_id,
B.title as blog_title,
B.author_id as blog_author_id,
A.id as author_id,
A.username as author_username,
A.password as author_password,
A.email as author_email,
A.bio as author_bio,
A.favourite_section as author_favourite_section,
P.id as post_id,
P.blog_id as post_blog_id,
P.author_id as post_author_id,
P.created_on as post_created_on,
P.section as post_section,
P.subject as post_subject,
P.draft as draft,
P.body as post_body,
C.id as comment_id,
C.post_id as comment_post_id,
C.name as comment_name,
C.comment as comment_text,
T.id as tag_id,
T.name as tag_name
from Blog B
left outer join Author A on B.author_id = A.id
left outer join Post P on B.id = P.blog_id
left outer join Comment C on P.id = C.post_id
left outer join Post_Tag PT on PT.post_id = P.id
left outer join Tag T on PT.tag_id = T.id
where B.id = #{id}
</select>
你可能想把它映射到一個智能的對象模型,包含一個作者寫的博客,有很多的博文,每 篇博文有零條或多條的評論和標籤。 下面是一個完整的複雜結果映射例子 (假設作者, 博客, 博文, 評論和標籤都是類型的別名) 我們來看看, 。 但是不用緊張, 我們會一步一步來說明。 當天最初它看起來令人生畏,但實際上非常簡單。
<!-- Very Complex Result Map -->
<resultMap id="detailedBlogResultMap" type="Blog">
<constructor>
<idArg column="blog_id" javaType="int"/>
</constructor>
<result property="title" column="blog_title"/>
<association property="author" javaType="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
<result property="password" column="author_password"/>
<result property="email" column="author_email"/>
<result property="bio" column="author_bio"/>
<result property="favouriteSection" column="author_favourite_section"/>
</association>
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<association property="author" javaType="Author"/>
<collection property="comments" ofType="Comment">
<id property="id" column="comment_id"/>
</collection>
<collection property="tags" ofType="Tag" >
<id property="id" column="tag_id"/>
</collection>
<discriminator javaType="int" column="draft">
<case value="1" resultType="DraftPost"/>
</discriminator>
</collection>
</resultMap>
resultMap 元素有很多子元素和一個值得討論的結構。 下面是 resultMap 元素的概念視圖
resultMap
constructor - 類在實例化時,用來注入結果到構造方法中
idArg - ID 參數;標記結果作爲 ID 可以幫助提高整體效能
arg- 注入到構造方法的一個普通結果
id – 一個 ID 結果;標記結果作爲 ID 可以幫助提高整體效能
result – 注入到字段或 JavaBean 屬性的普通結果
association – 一個複雜的類型關聯;許多結果將包成這種類型
嵌入結果映射 – 結果映射自身的關聯,或者參考一個
collection – 複雜類型的集
嵌入結果映射 – 結果映射自身的集,或者參考一個
discriminator – 使用結果值來決定使用哪個結果映射
case – 基於某些值的結果映射
嵌入結果映射 – 這種情形結果也映射它本身,因此可以包含很多相 同的元素,或者它可以參照一個外部的結果映射。
ResultMap Attributes
id:當前命名空間中的一個唯一標識,用於標識一個result map.
type:類的全限定名, 或者一個類型別名 (內置的別名可以參考上面的表格).
autoMapping:如果設置這個屬性,MyBatis將會爲這個ResultMap開啓或者關閉自動映射。這個屬性會覆蓋全局的屬性autoMappingBehavior。默認值爲:unset。
最佳實踐 通常逐步建立結果映射。單元測試的真正幫助在這裏。如果你嘗試創建 一次創建一個向上面示例那樣的巨大的結果映射, 那麼可能會有錯誤而且很難去控制它 來工作。開始簡單一些,一步一步的發展。而且要進行單元測試!使用該框架的缺點是 它們有時是黑盒(是否可見源代碼) 。你確定你實現想要的行爲的最好選擇是編寫單元 測試。它也可以你幫助得到提交時的錯誤。
下面一部分將詳細說明每個元素。
id & result
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
這些是結果映射最基本內容。id 和 result 都映射一個單獨列的值到簡單數據類型(字符 串,整型,雙精度浮點數,日期等)的單獨屬性或字段。
這兩者之間的唯一不同是 id 表示的結果將是當比較對象實例時用到的標識屬性。這幫 助來改進整體表現,特別是緩存和嵌入結果映射(也就是聯合映射) 。
每個都有一些屬性:
Id and Result Attributes
property:映射到列結果的字段或屬性。如果匹配的是存在的,和給定名稱相同 的 JavaBeans 的屬性,那麼就會使用。否則 MyBatis 將會尋找給定名稱 property 的字段。這兩種情形你可以使用通常點式的複雜屬性導航。比如,你 可以這樣映射一些東西: “username” ,或者映射到一些複雜的東西: “address.street.number” 。
column:從數據庫中得到的列名,或者是列名的重命名標籤。這也是通常和會 傳遞給 resultSet.getString(columnName)方法參數中相同的字符串。
javaType:一個 Java 類的完全限定名,或一個類型別名(參考上面內建類型別名 的列表) 。如果你映射到一個 JavaBean,MyBatis 通常可以斷定類型。 然而,如果你映射到的是 HashMap,那麼你應該明確地指定 javaType 來保證所需的行爲。
jdbcType:在這個表格之後的所支持的 JDBC 類型列表中的類型。JDBC 類型是僅 僅需要對插入,更新和刪除操作可能爲空的列進行處理。這是 JDBC jdbcType 的需要,而不是 MyBatis 的。如果你直接使用 JDBC 編程,你需要指定 這個類型-但僅僅對可能爲空的值。
typeHandler:我們在前面討論過默認的類型處理器。使用這個屬性,你可以覆蓋默 認的類型處理器。這個屬性值是類的完全限定名或者是一個類型處理 器的實現,或者是類型別名。
關注微信公衆號:IT哈哈(it_haha),學習更多知識。