MyBatis之Mapper XML 文件詳解(一)

MyBatis 的真正強大在於它的映射語句,也是它的魔力所在。由於它的異常強大,映射器的 XML 文件就顯得相對簡單。如果拿它跟具有相同功能的 JDBC 代碼進行對比,你會立即發現省掉了將近 95% 的代碼。MyBatis 就是針對 SQL 構建的,並且比普通的方法做的更好。
SQL 映射文件有很少的幾個頂級元素(按照它們應該被定義的順序):
cache – 給定命名空間的緩存配置。 
cache-ref – 其他命名空間緩存配置的引用。 
resultMap – 是最複雜也是最強大的元素,用來描述如何從數據庫結果集中來加載對象。 
parameterMap – 已廢棄!老式風格的參數映射。內聯參數是首選,這個元素可能在將來被移除,這裏不會記錄。 
sql – 可被其他語句引用的可重用語句塊。 
insert – 映射插入語句 
update – 映射更新語句 
delete – 映射刪除語句 
select – 映射查詢語句 


下一部分將從語句本身開始來描述每個元素的細節。


select
查詢語句是 MyBatis 中最常用的元素之一,光能把數據存到數據庫中價值並不大,如果還能重新取出來纔有用,多數應用也都是查詢比修改要頻繁。對每個插入、更新或刪除操作,通常對應多個查詢操作。這是 MyBatis 的基本原則之一,也是將焦點和努力放到查詢和結果映射的原因。簡單查詢的 select 元素是非常簡單的。比如:

<select id="selectPerson" parameterType="int" resultType="hashmap">
 SELECT * FROM PERSON WHERE ID = #{id}
</select>

這個語句被稱作 selectPerson,接受一個 int(或 Integer)類型的參數,並返回一個 HashMap 類型的對象,其中的鍵是列名,值便是結果行中的對應值。 
注意參數符號:

#{id}

這就告訴 MyBatis 創建一個預處理語句參數,通過 JDBC,這樣的一個參數在 SQL 中會由一個“?”來標識,並被傳遞到一個新的預處理語句中,就像這樣:

// Similar JDBC code, NOT MyBatis…
String selectPerson = "SELECT * FROM PERSON WHERE ID=?";
PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id);

當然,這需要很多單獨的 JDBC 的代碼來提取結果並將它們映射到對象實例中,這就是 MyBatis 節省你時間的地方。我們需要深入瞭解參數和結果映射,細節部分我們下面來了解。 


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">

Select Attributes

id:在命名空間中唯一的標識符,可以被用來引用這條語句。 
parameterType:將會傳入這條語句的參數類的完全限定名或別名。這個屬性是可選的,因爲 MyBatis 可以通過 TypeHandler 推斷出具體傳入語句的參數,默認值爲 unset。 
parameterMap :這是引用外部 parameterMap 的已經被廢棄的方法。使用內聯參數映射和 parameterType 屬性。 
resultType:從這條語句中返回的期望類型的類的完全限定名或別名。注意如果是集合情形,那應該是集合可以包含的類型,而不能是集合本身。使用 resultType 或 resultMap,但不能同時使用。 
resultMap:外部 resultMap 的命名引用。結果集的映射是 MyBatis 最強大的特性,對其有一個很好的理解的話,許多複雜映射的情形都能迎刃而解。使用 resultMap 或 resultType,但不能同時使用。 
flushCache:將其設置爲 true,任何時候只要語句被調用,都會導致本地緩存和二級緩存都會被清空,默認值:false。 
useCache:將其設置爲 true,將會導致本條語句的結果被二級緩存,默認值:對 select 元素爲 true。 
timeout:這個設置是在拋出異常之前,驅動程序等待數據庫返回請求結果的秒數。默認值爲 unset(依賴驅動)。 
fetchSize:這是嘗試影響驅動程序每次批量返回的結果行數和這個設置值相等。默認值爲 unset(依賴驅動)。 
statementType:STATEMENT,PREPARED 或 CALLABLE 的一個。這會讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認值:PREPARED。 
resultSetType:FORWARDONLY,SCROLLSENSITIVE 或 SCROLL_INSENSITIVE 中的一個,默認值爲 unset (依賴驅動)。 
databaseId:如果配置了 databaseIdProvider,MyBatis 會加載所有的不帶 databaseId 或匹配當前 databaseId 的語句;如果帶或者不帶的語句都有,則不帶的會被忽略。 
resultOrdered:這個設置僅針對嵌套結果 select 語句適用:如果爲 true,就是假設包含了嵌套結果集或是分組了,這樣的話當返回一個主結果行的時候,就不會發生有對前面結果集的引用的情況。這就使得在獲取嵌套的結果集的時候不至於導致內存不夠用。默認值:false。 
resultSets:這個設置僅對多結果集的情況適用,它將列出語句執行後返回的結果集並每個結果集給一個名稱,名稱是逗號分隔的。 

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 's Attributes

id:命名空間中的唯一標識符,可被用來代表這條語句。
parameterType:將要傳入語句的參數的完全限定類名或別名。這個屬性是可選的,因爲 MyBatis 可以通過 TypeHandler 推斷出具體傳入語句的參數,默認值爲 unset。 
parameterMap :這是引用外部 parameterMap 的已經被廢棄的方法。使用內聯參數映射和 parameterType 屬性。 
flushCache:將其設置爲 true,任何時候只要語句被調用,都會導致本地緩存和二級緩存都會被清空,默認值:true(對應插入、更新和刪除語句)。 
timeout:這個設置是在拋出異常之前,驅動程序等待數據庫返回請求結果的秒數。默認值爲 unset(依賴驅動)。 
statementType:STATEMENT,PREPARED 或 CALLABLE 的一個。這會讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認值:PREPARED。 
useGeneratedKeys:(僅對 insert 和 update 有用)這會令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來取出由數據庫內部生成的主鍵(比如:像 MySQL 和 SQL Server 這樣的關係數據庫管理系統的自動遞增字段),默認值:false。 
keyProperty:(僅對 insert 和 update 有用)唯一標記一個屬性,MyBatis 會通過 getGeneratedKeys 的返回值或者通過 insert 語句的 selectKey 子元素設置它的鍵值,默認:unset。如果希望得到多個生成的列,也可以是逗號分隔的屬性名稱列表。 
keyColumn:(僅對 insert 和 update 有用)通過生成的鍵值設置表中的列名,這個設置僅在某些數據庫(像 PostgreSQL)是必須的,當主鍵列不是表中的第一列的時候需要設置。如果希望得到多個生成的列,也可以是逗號分隔的屬性名稱列表。 
databaseId:如果配置了 databaseIdProvider,MyBatis 會加載所有的不帶 databaseId 或匹配當前 databaseId 的語句;如果帶或者不帶的語句都有,則不帶的會被忽略。 


下面就是 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>

對於不支持自動生成類型的數據庫或可能不支持自動生成主鍵 JDBC 驅動來說,MyBatis 有另外一種方法來生成主鍵。 


這裏有一個簡單(甚至很傻)的示例,它可以生成一個隨機 ID(你最好不要這麼做,但這裏展示了 MyBatis 處理問題的靈活性及其所關心的廣度):

<insert id="insertAuthor">
 <selectKey keyProperty="id" resultType="int" order="BEFORE">
   select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1
 </selectKey>
 insert into Author
   (id, username, password, email,bio, favourite_section)
 values
   (#{id}, #{username}, #{password}, #{email}, #{bio}, #{favouriteSection,jdbcType=VARCHAR})
</insert>

在上面的示例中,selectKey 元素將會首先運行,Author 的 id 會被設置,然後插入語句會被調用。這給你了一個和數據庫中來處理自動生成的主鍵類似的行爲,避免了使 Java 代碼變得複雜。 


selectKey 元素描述如下:

<selectKey
 keyProperty="id"
 resultType="int"
 order="BEFORE"
 statementType="PREPARED">

selectKey Attributes

keyProperty:selectKey 語句結果應該被設置的目標屬性。如果希望得到多個生成的列,也可以是逗號分隔的屬性名稱列表。 
keyColumn:匹配屬性的返回結果集中的列名稱。如果希望得到多個生成的列,也可以是逗號分隔的屬性名稱列表。 
resultType:結果的類型。MyBatis 通常可以推算出來,但是爲了更加確定寫上也不會有什麼問題。MyBatis 允許任何簡單類型用作主鍵的類型,包括字符串。如果希望作用於多個生成的列,則可以使用一個包含期望屬性的 Object 或一個 Map。 
order:這可以被設置爲 BEFORE 或 AFTER。如果設置爲 BEFORE,那麼它會首先選擇主鍵,設置 keyProperty 然後執行插入語句。如果設置爲 AFTER,那麼先執行插入語句,然後是 selectKey 元素 - 這和像 Oracle 的數據庫相似,在插入語句內部可能有嵌入索引調用。 
statementType:與前面相同,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 語句的映射類型,分別代表 PreparedStatement 和 CallableStatement 類型。

關注微信公衆號:IT哈哈(it_haha),學習更多內容。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章