Mybatis之mapper XML 檔案
Mybatis之mapper XML 檔案
原文連結:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html
一、mapper XML 檔案
MyBatis 的真正強大在於它的對映語句,也是它的魔力所在。由於它的異常強大,對映器的 XML 檔案就顯得相對簡單。如果拿它跟具有相同功能的 JDBC 程式碼進行對比,你會立即發現省掉了將近 95% 的程式碼。MyBatis 就是針對 SQL 構建的,並且比普通的方法做的更好。
SQL 對映檔案有很少的幾個頂級元素(按照它們應該被定義的順序):
- cache – 給定名稱空間的快取配置。
- cache-ref – 其他名稱空間快取配置的引用。
- resultMap – 是最複雜也是最強大的元素,用來描述如何從資料庫結果集中來載入物件。
parameterMap – 已廢棄!老式風格的引數對映。內聯引數是首選,這個元素可能在將來被移除,這裡不會記錄。- sql – 可被其他語句引用的可重用語句塊。
- insert – 對映插入語句
- update – 對映更新語句
- delete – 對映刪除語句
- select – 對映查詢語句
下一部分將從語句本身開始來描述每個元素的細節。
1.1、select
查詢語句是 MyBatis 中最常用的元素之一,光能把資料存到資料庫中價值並不大,如果還能重新取出來才有用,多數應用也都是查詢比修改要頻繁。對每個插入、更新或刪除操作,通常對應多個查詢操作。這是 MyBatis 的基本原則之一,也是將焦點和努力放到查詢和結果對映的原因。簡單查詢的 select 元素是非常簡單的。比如:
<select id="selectPerson" parameterType="int" resultType="hashmap">
SELECT * FROM PERSON WHERE ID = #{id}
</select>
這個語句被稱作 selectPerson,接受一個 int(或 Integer)型別的引數,並返回一個 HashMap 型別的物件,其中的鍵是列名,值便是結果行中的對應值select 元素有很多屬性允許你配置,來決定每條語句的作用細節。
<select id="selectPerson" parameterType="int" parameterMap="deprecated" resultType="hashmap" resultMap="personResultMap" flushCache="false" useCache="true" timeout="10000" fetchSize="256" statementType="PREPARED" resultSetType="FORWARD_ONLY">
1.2、insert,update 和 delete
資料變更語句 insert,update 和 delete 的實現非常接近:
<insert
id="insertAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
keyProperty=""
keyColumn=""
useGeneratedKeys=""
timeout="20">
<update
id="updateAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">
<delete
id="deleteAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">
下面就是 insert,update 和 delete 語句的示例:
<insert id="insertAuthor">
insert into Author (id,username,password,email,bio)
values (#{id},#{username},#{password},#{email},#{bio})
</insert>
<update id="updateAuthor">
update Author set
username = #{username},
password = #{password},
email = #{email},
bio = #{bio}
where id = #{id}
</update>
<delete id="deleteAuthor">
delete from Author where id = #{id}
</delete>
如前所述,插入語句的配置規則更加豐富,在插入語句裡面有一些額外的屬性和子元素用來處理主鍵的生成,而且有多種生成方式。
首先,如果你的資料庫支援自動生成主鍵的欄位(比如 MySQL 和 SQL Server),那麼你可以設定 useGeneratedKeys=”true”,然後再把 keyProperty 設定到目標屬性上就OK了。例如,如果上面的 Author 表已經對 id 使用了自動生成的列型別,那麼語句可以修改為:
<insert id="insertAuthor" useGeneratedKeys="true"
keyProperty="id">
insert into Author (username,password,email,bio)
values (#{username},#{password},#{email},#{bio})
</insert>
如果你的資料庫還支援多行插入, 你也可以傳入一個Authors陣列或集合,並返回自動生成的主鍵
<insert id="insertAuthor" useGeneratedKeys="true"
keyProperty="id">
insert into Author (username, password, email, bio) values
<foreach item="item" collection="list" separator=",">
(#{item.username}, #{item.password}, #{item.email}, #{item.bio})
</foreach>
</insert>
1.3、SQL
這個元素可以被用來定義可重用的 SQL 程式碼段,可以包含在其他語句中。它可以被靜態地(在載入引數) 引數化. 不同的屬性值通過包含的例項變化. 比如:
<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql
這個 SQL 片段可以被包含在其他語句中,例如:
<select id="selectUsers" resultType="map">
select
<include refid="userColumns"><property name="alias" value="t1"/></include>,
<include refid="userColumns"><property name="alias" value="t2"/></include>
from some_table t1
cross join some_table t2
</select>
屬性值可以用於包含的refid屬性或者包含的字句裡面的屬性值,例如:
<sql id="sometable">
${prefix}Table
</sql>
<sql id="someinclude">
from
<include refid="${include_target}"/>
</sql>
<select id="select" resultType="map">
select
field1, field2, field3
<include refid="someinclude">
<property name="prefix" value="Some"/>
<property name="include_target" value="sometable"/>
</include>
</select>
1.4、ResultMap
resultMap 元素是 MyBatis 中最重要最強大的元素。它就是讓你遠離 90%的需要從結果集中取出資料的 JDBC 程式碼的那個東西,而且在一些情形下允許你做一些 JDBC 不支援的事情。事實上,編寫相似於對複雜語句聯合對映這些等同的程式碼,也許可以跨過上千行的程式碼。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>
高階結果對映
resultMap
- constructor - 類在例項化時,用來注入結果到構造方法中
- idArg - ID 引數;標記結果作為 ID 可以幫助提高整體效能
- arg - 注入到構造方法的一個普通結果
- id – 一個 ID 結果;標記結果作為 ID 可以幫助提高整體效能
- result – 注入到欄位或 JavaBean 屬性的普通結果
- association – 一個複雜的型別關聯;許多結果將包成這種型別
- 嵌入結果對映 – 結果對映自身的關聯,或者參考一個
- collection – 複雜型別的集
- 嵌入結果對映 – 結果對映自身的集,或者參考一個
- discriminator – 使用結果值來決定使用哪個結果對映
- case – 基於某些值的結果對映
- 嵌入結果對映 – 這種情形結果也對映它本身,因此可以包含很多相 同的元素,或者它可以參照一個外部的結果對映。
- case – 基於某些值的結果對映
關聯
<association property="author" column="blog_author_id" javaType="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
</association>
關聯元素處理“有一個”型別的關係。比如,在我們的示例中,一個部落格有一個使用者。關聯對映就工作於這種結果之上。你指定了目標屬性,來獲取值的列,屬性的 java 型別(很多情況下 MyBatis 可以自己算出來),如果需要的話還有 jdbc 型別,如果你想覆蓋或獲取的結果值還需要型別控制器。
關聯中不同的是你需要告訴 MyBatis 如何載入關聯。MyBatis 在這方面會有兩種不同的方式:
- 巢狀查詢:通過執行另外一個 SQL 對映語句來返回預期的複雜型別。
- 巢狀結果:使用巢狀結果對映來處理重複的聯合結果的子集。首先,然讓我們來檢視這個元素的屬性。所有的你都會看到,它和普通的只由 select 和
resultMap 屬性的結果對映不同。
<resultMap id="blogResult" type="Blog">
<association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>
<select id="selectBlog" resultMap="blogResult">
SELECT * FROM BLOG WHERE ID = #{id}
</select>
<select id="selectAuthor" resultType="Author">
SELECT * FROM AUTHOR WHERE ID = #{id}
</select
我們有兩個查詢語句:一個來載入部落格,另外一個來載入作者,而且部落格的結果對映描述了“selectAuthor”語句應該被用來載入它的 author 屬性。
其他所有的屬性將會被自動載入,假設它們的列和屬性名相匹配。
集合(一對多對映)
<collection property="posts" ofType="domain.blog.Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<result property="body" column="post_body"/>
</collection>
集合元素的作用幾乎和關聯是相同的。實際上,它們也很相似,文件的異同是多餘的。所以我們更多關注於它們的不同。
我們來繼續上面的示例,一個部落格只有一個作者。但是部落格有很多文章。在部落格類中,這可以由下面這樣的寫法來表示:
private List<Post> posts;
要對映巢狀結果集合到 List 中,我們使用集合元素。就像關聯元素一樣,我們可以從連線中使用巢狀查詢,或者巢狀結果。集合的巢狀查詢
首先,讓我們看看使用巢狀查詢來為部落格載入文章<resultMap id="blogResult" type="Blog">
<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
</resultMap>
<select id="selectBlog" resultMap="blogResult">
SELECT * FROM BLOG WHERE ID = #{id}
</select>
<select id="selectPostsForBlog" resultType="Post">
SELECT * FROM POST WHERE BLOG_ID = #{id}
</select>
這裡你應該注意很多東西,但大部分程式碼和上面的關聯元素是非常相似的。首先,你應該注意我們使用的是集合元素。然後要注意那個新的“ofType”屬性。這個屬性用來區分JavaBean(或欄位)屬性型別和集合包含的型別來說是很重要的。所以你可以讀出下面這個對映:
<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
讀作: “在 Post 型別的 ArrayList 中的 posts 的集合。”
javaType 屬性是不需要的,因為 MyBatis 在很多情況下會為你算出來。所以你可以縮短寫法:
<collection property="posts" column="id" ofType="Post" select="selectPostsForBlog"/>
集合的巢狀結果
<select id="selectBlog" resultMap="blogResult">
select
B.id as blog_id,
B.title as blog_title,
B.author_id as blog_author_id,
P.id as post_id,
P.subject as post_subject,
P.body as post_body,
from Blog B
left outer join Post P on B.id = P.blog_id
where B.id = #{id}
</select>
在用文章對映集合對映部落格,可以簡單寫為:
<resultMap id="blogResult" type="Blog">
<id property="id" column="blog_id" />
<result property="title" column="blog_title"/>
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<result property="body" column="post_body"/>
</collection>
</resultMap>
同樣,要記得 id 元素的重要性,如果你不記得了,請閱讀上面的關聯部分。
同樣,如果你引用更長的形式允許你的結果對映的更多重用,你可以使用下面這個替代的對映:
<resultMap id="blogResult" type="Blog">
<id property="id" column="blog_id" />
<result property="title" column="blog_title"/>
<collection property="posts" ofType="Post" resultMap="blogPostResult" columnPrefix="post_"/>
</resultMap>
<resultMap id="blogPostResult" type="Post">
<id property="id" column="id"/>
<result property="subject" column="subject"/>
<result property="body" column="body"/>
</resultMap>