Mybatis 3.1中 Mapper XML 文件 的學習詳解

MyBatis 真正的力量是在映射語句中。這裏是奇蹟發生的地方。對於所有的力量,SQL 映射的 XML 文件是相當的簡單。當然如果你將它們和對等功能的 JDBC 代碼來比較,你會發現映射文件節省了大約 95%的代碼量。MyBatis 的構建就是聚焦於 SQL 的,使其遠離於普通的方式。

SQL 映射文件有很少的幾個頂級元素(按照它們應該被定義的順序):

  • cache – 配置給定命名空間的緩存。
  • cache-ref – 從其他命名空間引用緩存配置。
  • resultMap – 最複雜,也是最有力量的元素,用來描述如何從數據庫結果集中來加載你的對象。
  • parameterMap – 已經被廢棄了!老式風格的參數映射。內聯參數是首選,這個元素可能在將來被移除。這裏不會記錄。
  • sql – 可以重用的 SQL 塊,也可以被其他語句引用。
  • insert – 映射插入語句
  • update – 映射更新語句
  • delete – 映射刪除語句
  • select – 映射查詢語句

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

select

查詢語句是使用 MyBatis 時最常用的元素之一。直到你從數據庫取出數據時纔會發現將數據存在數據庫中是多麼的有價值, 所以許多應用程序查詢要比更改數據多的多。對於每次插入,更新或刪除,那也會有很多的查詢。這是 MyBatis 的一個基本原則,也是將重心和努力放到查詢和結果映射的原因。對簡單類別的查詢元素是非常簡單的。比如:

<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 將會傳入這條語句的參數類的完全限定名或別名。
parameterMap 這是引用外部 parameterMap 的已經被廢棄的方法。使用內聯參數映射和 parameterType 屬性。
resultType 從這條語句中返回的期望類型的類的完全限定名或別名。注意集合情形,那應該是集合可以包含的類型,而不能是集合本身。使用 resultType 或 resultMap,但不能同時使用。
resultMap 命名引用外部的 resultMap。返回 map 是 MyBatis 最具力量的特性, 對其有一個很好的理解的話, 許多複雜映射的情形就能被解決了。使用 resultMap 或 resultType,但不能同時使用。
flushCache 將其設置爲 true,不論語句什麼時候被帶哦用,都會導致緩存被清空。默認值:false。
useCache 將其設置爲 true, 將會導致本條語句的結果被緩存。默認值: true。
timeout 這個設置驅動程序等待數據庫返回請求結果,並拋出異常時間的最大等待值。默認不設置(驅動自行處理)
fetchSize 這是暗示驅動程序每次批量返回的結果行數。默認不設置(驅動自行處理)。
statementType STA TEMENT,PREPARED 或 CALLABLE 的一種。這會讓 MyBatis 使用選擇使用 Statement,PreparedStatement 或 CallableStatement。默認值:PREPARED。
resultSetType FORWARD_ONLY|SCROLL_SENSITIVE|SCROLL_INSENSITIVE 中的一種。默認是不設置(驅動自行處理)。
databaseId In case there is a configured databaseIdProvider, MyBatis will load all statements with no databaseId attribute or with a databaseId that matches the current one. If case the same statement if found with and without the databaseId the latter will be discarded.

insert, update and delete

數據變更語句 insert,update 和 delete 在它們的實現中非常相似:

<insert   id="insertAuthor"   parameterType="domain.blog.Author"   flushCache="true"   statementType="PREPARED"   keyProperty=""   keyColumn=""   useGeneratedKeys=""   timeout="20000"> <update   id="insertAuthor"   parameterType="domain.blog.Author"   flushCache="true"   statementType="PREPARED"   timeout="20000"> <delete   id="insertAuthor"   parameterType="domain.blog.Author"   flushCache="true"   statementType="PREPARED"   timeout="20000">
Insert, Update and Delete Attributes
屬性 描述
id 在命名空間中唯一的標識符,可以被用來引用這條語句。
parameterType 將會傳入這條語句的參數類的完全限定名或別名。
parameterMap 這是引用外部 parameterMap 的已經被廢棄的方法。使用內聯參數映射和 parameterType 屬性。
flushCache 將其設置爲 true,不論語句什麼時候被帶哦用,都會導致緩存被清空。默認值:false。
timeout 這個設置驅動程序等待數據庫返回請求結果, 並拋出異常時間的最大等待值。默認不設置(驅動自行處理)。
statementType STA TEMENT,PREPARED 或 CALLABLE 的一種。這會讓 MyBatis 使用選擇使用 Statement,PreparedStatement 或 CallableStatement。默認值:PREPARED。
useGeneratedKeys ( 僅 對 insert 有 用 ) 這 會 告 訴 MyBatis 使 用 JDBC 的 getGeneratedKeys 方法來取出由數據(比如:像 MySQL 和 SQL Server 這樣的數據庫管理系統的自動遞增字段)內部生成的主鍵。默認值:false。
keyProperty (僅對 insert 有用) 標記一個屬性, MyBatis 會通過 getGeneratedKeys 或者通過 insert 語句的 selectKey 子元素設置它的值。默認: 不設置。
keyColumn (僅對 insert 有用) 標記一個屬性, MyBatis 會通過 getGeneratedKeys 或者通過 insert 語句的 selectKey 子元素設置它的值。默認: 不設置。

下面就是 insert,update 和 delete 語句的示例:

<insert id="insertAuthor" parameterType="domain.blog.Author">   insert into Author (id,username,password,email,bio)
  values (#{id},#{username},#{password},#{email},#{bio})</insert> <update id="updateAuthor" parameterType="domain.blog.Author">   update Author set
    username = #{username},
    password = #{password},
    email = #{email},
    bio = #{bio}
  where id = #{id}</update> <delete id="deleteAuthor" parameterType="int">   delete from Author where id = #{id}</delete>

如前所述,插入語句有一點多,它有一些屬性和子元素用來處理主鍵的生成。

首先,如果你的數據庫支持自動生成主鍵的字段(比如 MySQL 和 SQL Server) ,那麼你可以設置 useGeneratedKeys=”true”,而且設置 keyProperty 到你已經做好的目標屬性上。例如,如果上面的 Author 表已經對 id 使用了自動生成的列類型,那麼語句可以修改爲:

<insert id="insertAuthor" parameterType="domain.blog.Author" useGeneratedKeys="true"     keyProperty="id">   insert into Author (username,password,email,bio)
  values (#{username},#{password},#{email},#{bio})</insert>

MyBatis 有另外一種方法來處理數據庫不支持自動生成類型,或者可能 JDBC 驅動不支持自動生成主鍵時的主鍵生成問題。

這裏有一個簡單(甚至很傻)的示例,它可以生成一個隨機 ID(可能你不會這麼做, 但是這展示了 MyBatis 處理問題的靈活性,因爲它並不真的關心 ID 的生成):

<insert id="insertAuthor" parameterType="domain.blog.Author">   <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 語句結果應該被設置的目標屬性。
resultType 結果的類型。MyBatis 通常可以算出來,但是寫上也沒有問題。 MyBatis 允許任何簡單類型用作主鍵的類型,包括字符串。
order 這可以被設置爲 BEFORE 或 AFTER。如果設置爲 BEFORE,那麼它會首先選擇主鍵, 設置 keyProperty 然後執行插入語句。如果設置爲 AFTER,那麼先執行插入語句,然後是 selectKey 元素- 這和如 Oracle 數據庫相似,可以在插入語句中嵌入序列調用。
statementType 和前面的相 同,MyBatis 支持 STA TEMENT ,PREPARED 和 CALLABLE 語句的映射類型,分別代表 PreparedStatement 和 CallableStatement 類型。

sql

這個元素可以被用來定義可重用的 SQL 代碼段,可以包含在其他語句中。比如:

<sql id="userColumns"> id,username,password </sql>

這個 SQL 片段可以被包含在其他語句中,例如:

<select id="selectUsers" parameterType="int" resultType="hashmap">   select <include refid="userColumns"/>   from some_table
  where id = #{id}</select>

Parameters

在之前的語句中, 你已經看到了一些簡單參數的示例。 MyBatis 中參數是非常強大的在元素。對於簡單的做法,大概 90%的情況,是不用太多的,比如:

<select id="selectUsers" parameterType="int" resultType="User">   select id, username, password
  from users
  where id = #{id}</select>

上面的這個示例說明了一個非常簡單的命名參數映射。參數類型被設置爲“int” ,因此這個參數可以被設置成任何內容。原生的類型或簡單數據類型, 比如整型和沒有相關屬性的字符串,因此它會完全用參數來替代。然而,如果你傳遞了一個複雜的對象,那麼 MyBatis 的處理方式就會有一點不同。比如:

<insert id="insertUser" parameterType="User" >   insert into users (id, username, password)
  values (#{id}, #{username}, #{password})</insert>

如果 User 類型的參數對象傳遞到了語句中, username 和 password 屬性將會被查找, id、然後它們的值就被傳遞到預處理語句的參數中。

這點對於傳遞參數到語句中非常好。但是對於參數映射也有一些其他的特性。

首先,像 MyBatis 的其他部分,參數可以指定一個確定的數據類型。

#{property,javaType=int,jdbcType=NUMERIC}

像 MyBatis 的剩餘部分,javaType 通常可以從參數對象中來去頂,除非對象是一個 HashMap。那麼 javaType 應該被確定來保證使用正確類型處理器。

注意 如果 null 被當作值來傳遞,對於所有可能爲空的列,JDBC Type 是需要的。以可以自己通過閱讀預處理語句的 setNull()方法的 JavaDocs 文檔來研究這個。

爲了自定義類型處理器,你可以指定一個確定的類型處理器類(或別名), 比如:

#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}

儘管它看起來繁瑣,但是實際上是你很少設置它們其中之一。

對於數值類型,對於決定有多少數字是相關的,有一個數值範圍。

#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}

最後,mode 屬性允許你指定 IN,OUT 或 INOUT 參數。如果參數爲 OUT 或 INOUT, 參數對象屬性的真實值將會被改變,就像你期望你需要你個輸出參數。如果 mode 爲 OUT (或 INOUT) ,而且 jdbcType 爲 CURSOR(也就是 Oracle 的 REFCURSOR) ,你必須指定一個 resultMap 來映射結果集到參數類型。要注意這裏的 javaType 屬性是可選的,如果左邊的空白是 jdbcType 的 CURSOR 類型,它會自動地被設置爲結果集。

#{department, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=departmentResultMap}

MyBatis 也支持很多高級的數據類型,比如結構體,但是當註冊 out 參數時你必須告訴語句類型名稱。比如(再次提示,在實際中不要像這樣換行):

#{middleInitial, mode=OUT, jdbcType=STRUCT, jdbcTypeName=MY_TYPE, resultMap=departmentResultMap}

儘管所有這些強大的選項很多時候你只簡單指定屬性名,MyBatis 會自己計算剩餘的。最多的情況是你爲 jdbcType 指定可能爲空的列名。

#{firstName} #{middleInitial,jdbcType=VARCHAR} #{lastName}

字符串替換

默認情況下,使用#{}格式的語法會導致 MyBatis 創建預處理語句屬性並以它爲背景設置安全的值(比如?) 。這樣做很安全,很迅速也是首選做法,有時你只是想直接在 SQL 語句中插入一個不改變的字符串。比如,像 ORDER BY,你可以這樣來使用:

ORDER BY ${columnName}

這裏 MyBatis 不會修改或轉義字符串。

重要 接受從用戶輸出的內容並提供給語句中不變的字符串,這樣做是不安全的。這會導致潛在的 SQL 注入攻擊,因此你不應該允許用戶輸入這些字段,或者通常自行轉義並檢查。

Result Maps

resultMap 元素是 MyBatis 中最重要最強大的元素。它就是讓你遠離 90%的需要從結果集中取出數據的 JDBC 代碼的那個東西, 而且在一些情形下允許你做一些 JDBC 不支持的事情。事實上, 編寫相似於對複雜語句聯合映射這些等同的代碼, 也許可以跨過上千行的代碼。 ResultMap 的設計就是簡單語句不需要明確的結果映射,而很多複雜語句確實需要描述它們的關係。

你已經看到簡單映射語句的示例了,但沒有明確的 resultMap。比如:

<select id="selectUsers" parameterType="int" resultType="hashmap">   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" parameterType="int" 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" parameterType="int" resultType="User">   select id, username, hashedPassword
  from some_table
  where id = #{id}</select>

這些情況下,MyBatis 會在幕後自動創建一個 ResultMap,基於屬性名來映射列到 JavaBean 的屬性上。如果列名沒有精確匹配,你可以在列名上使用 select 字句的別名(一個基本的 SQL 特性)來匹配標籤。比如:

<select id="selectUsers" parameterType="int" 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="username"/>   <result property="password" column="password"/> </resultMap>

引用它的語句使用 resultMap 屬性就行了(注意我們去掉了 resultType 屬性)。比如:

<select id="selectUsers" parameterType="int" 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" parameterType="int" 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 – 基於某些值的結果映射
      • 嵌入結果映射 – 這種情形結果也映射它本身,因此可以包含很多相 同的元素,或者它可以參照一個外部的結果映射。

最佳實踐 通常逐步建立結果映射。單元測試的真正幫助在這裏。如果你嘗試創建一次創建一個向上面示例那樣的巨大的結果映射, 那麼可能會有錯誤而且很難去控制它來工作。開始簡單一些,一步一步的發展。而且要進行單元測試!使用該框架的缺點是它們有時是黑盒(是否可見源代碼) 。你確定你實現想要的行爲的最好選擇是編寫單元測試。它也可以你幫助得到提交時的錯誤。

下面一部分將詳細說明每個元素。

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 我們在前面討論過默認的類型處理器。使用這個屬性,你可以覆蓋默認的類型處理器。這個屬性值是類的完全限定名或者是一個類型處理器的實現,或者是類型別名。

支持的 JDBC 類型

爲了未來的參考,MyBatis 通過包含的 jdbcType 枚舉型,支持下面的 JDBC 類型。

BIT FLOAT CHAR TIMESTAMP OTHER UNDEFINED
TINYINT REAL VARCHAR BINARY BLOG NVARCHAR
SMALLINT DOUBLE LONGVARCHAR VARBINARY CLOB >NCHAR
INTEGER NUMERIC DATE LONGVARBINARY BOOLEAN NCLOB
BIGINT DECIMAL TIME NULL CURSOR ARRAY

構造方法

<constructor>    <idArg column="id" javaType="int"/>    <arg column="username" javaType="String"/> </constructor>

對於大多數數據傳輸對象(Data Transfer Object,DTO)類型,屬性可以起作用,而且像你絕大多數的領域模型, 指令也許是你想使用一成不變的類的地方。通常包含引用或查詢數據的表很少或基本不變的話對一成不變的類來說是合適的。構造方法注入允許你在初始化時爲類設置屬性的值,而不用暴露出公有方法。MyBatis 也支持私有屬性和私有 JavaBeans 屬性來達到這個目的,但是一些人更青睞構造方法注入。構造方法元素支持這個。

看看下面這個構造方法:

public class User {    //...    public User(int id, String username) {      //...   } //... }

爲了向這個構造方法中注入結果,MyBatis 需要通過它的參數的類型來標識構造方法。 Java 沒有自查(反射)參數名的方法。所以當創建一個構造方法元素時,保證參數是按順序排列的,而且數據類型也是確定的。

<constructor>    <idArg column="id" javaType="int"/>    <arg column="username" javaType="String"/> </constructor>

剩餘的屬性和規則和固定的 id 和 result 元素是相同的。

屬性 描述
column 來自數據庫的類名,或重命名的列標籤。這和通常傳遞給 resultSet.getString(columnName)方法的字符串是相同的。
javaType 一個 Java 類的完全限定名,或一個類型別名(參加上面內建類型別名的列表)。如果你映射到一個 JavaBean,MyBatis 通常可以斷定類型。然而,如果你映射到的是 HashMap,那麼你應該明確地指定 javaType 來保證所需的行爲。
jdbcType 在這個表格之前的所支持的 JDBC 類型列表中的類型。JDBC 類型是僅僅需要對插入, 更新和刪除操作可能爲空的列進行處理。這是 JDBC 的需要, jdbcType 而不是 MyBatis 的。如果你直接使用 JDBC 編程,你需要指定這個類型-但僅僅對可能爲空的值。
typeHandler 我們在前面討論過默認的類型處理器。使用這個屬性,你可以覆蓋默認的類型處理器。這個屬性值是類的完全限定名或者是一個類型處理器的實現, 或者是類型別名。
select The ID of another mapped statement that will load the complex type required by this property mapping. The values retrieved from columns specified in the column attribute will be passed to the target select statement as parameters. See the Association element for more.
resultMap This is the ID of a ResultMap that can map the nested results of this argument into an appropriate object graph. This is an alternative to using a call to another select statement. It allows you to join multiple tables together into a single ResultSet. Such a ResultSet will contain duplicated, repeating groups of data that needs to be decomposed and mapped properly to a nested object graph. To facilitate this, MyBatis lets you "chain" result maps together, to deal with the nested results. See the Association element below for more.

關聯

<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 屬性的結果映射不同。

屬性 描述
property 映射到列結果的字段或屬性。如果匹配的是存在的,和給定名稱相同的 property JavaBeans 的屬性, 那麼就會使用。否則 MyBatis 將會尋找給定名稱的字段。這兩種情形你可以使用通常點式的複雜屬性導航。比如,你可以這樣映射一 些 東 西 :“ username ”, 或 者 映 射 到 一 些 復 雜 的 東 西 : “address.street.number” 。
javaType 一個 Java 類的完全限定名,或一個類型別名(參加上面內建類型別名的列表) 。如果你映射到一個 JavaBean,MyBatis 通常可以斷定類型。然而,如 javaType 果你映射到的是 HashMap,那麼你應該明確地指定 javaType 來保證所需的行爲。
jdbcType 在這個表格之前的所支持的 JDBC 類型列表中的類型。JDBC 類型是僅僅需要對插入, 更新和刪除操作可能爲空的列進行處理。這是 JDBC 的需要, jdbcType 而不是 MyBatis 的。如果你直接使用 JDBC 編程,你需要指定這個類型-但僅僅對可能爲空的值。
typeHandler 我們在前面討論過默認的類型處理器。使用這個屬性,你可以覆蓋默認的 typeHandler 類型處理器。這個屬性值是類的完全限定名或者是一個類型處理器的實現, 或者是類型別名。

關聯的嵌套查詢

屬性 描述
column 來自數據庫的類名,或重命名的列標籤。這和通常傳遞給 resultSet.getString(columnName)方法的字符串是相同的。 column 注 意 : 要 處 理 復 合 主 鍵 , 你 可 以 指 定 多 個 列 名 通 過 column= ” {prop1=col1,prop2=col2} ” 這種語法來傳遞給嵌套查詢語 句。這會引起 prop1 和 prop2 以參數對象形式來設置給目標嵌套查詢語句。
select 另外一個映射語句的 ID,可以加載這個屬性映射需要的複雜類型。獲取的在列屬性中指定的列的值將被傳遞給目標 select 語句作爲參數。表格後面有一個詳細的示例。 select 注 意 : 要 處 理 復 合 主 鍵 , 你 可 以 指 定 多 個 列 名 通 過 column= ” {prop1=col1,prop2=col2} ” 這種語法來傳遞給嵌套查詢語 句。這會引起 prop1 和 prop2 以參數對象形式來設置給目標嵌套查詢語句。

示例:

<resultMap id="blogResult" type="Blog">   <association property="author" column="blog_author_id" javaType="Author" select="selectAuthor"/> </resultMap> <select id="selectBlog" parameterType="int" resultMap="blogResult">   SELECT * FROM BLOG WHERE ID = #{id}</select> <select id="selectAuthor" parameterType="int" resultType="Author">   SELECT * FROM AUTHOR WHERE ID = #{id}</select>

我們有兩個查詢語句:一個來加載博客,另外一個來加載作者,而且博客的結果映射描述了“selectAuthor”語句應該被用來加載它的 author 屬性。

其他所有的屬性將會被自動加載,假設它們的列和屬性名相匹配。

這種方式很簡單, 但是對於大型數據集合和列表將不會表現很好。問題就是我們熟知的 “N+1 查詢問題”。概括地講,N+1 查詢問題可以是這樣引起的:

  • 你執行了一個單獨的 SQL 語句來獲取結果列表(就是“+1”)。
  • 對返回的每條記錄,你執行了一個查詢語句來爲每個加載細節(就是“N”)。

這個問題會導致成百上千的 SQL 語句被執行。這通常不是期望的。

MyBatis 能延遲加載這樣的查詢就是一個好處,因此你可以分散這些語句同時運行的消耗。然而,如果你加載一個列表,之後迅速迭代來訪問嵌套的數據,你會調用所有的延遲加載,這樣的行爲可能是很糟糕的。

所以還有另外一種方法。

關聯的嵌套結果

屬性 描述
resultMap 這是結果映射的 ID,可以映射關聯的嵌套結果到一個合適的對象圖中。這是一種替代方法來調用另外一個查詢語句。這允許你聯合多個表來合成到 resultMap 一個單獨的結果集。這樣的結果集可能包含重複,數據的重複組需要被分解,合理映射到一個嵌套的對象圖。爲了使它變得容易,MyBatis 讓你“鏈接”結果映射,來處理嵌套結果。一個例子會很容易來仿照,這個表格後面也有一個示例。
columnPrefix When joining multiple tables, you would have to use column alias to avoid duplicated column names in the ResultSet. Specifying columnPrefix allows you to map such columns to an external resultMap. Please see the example explained later in this section.

在上面你已經看到了一個非常複雜的嵌套關聯的示例。下面這個是一個非常簡單的示例來說明它如何工作。代替了執行一個分離的語句,我們聯合博客表和作者表在一起,就像:

<select id="selectBlog" parameterType="int" resultMap="blogResult">   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
  from Blog B left outer join Author A on B.author_id = A.id
  where B.id = #{id}</select>

注意這個聯合查詢, 以及採取保護來確保所有結果被唯一而且清晰的名字來重命名。這使得映射非常簡單。現在我們可以映射這個結果:

<resultMap id="blogResult" type="Blog">   <id property="id" column="blog_id" />   <result property="title" column="blog_title"/>   <association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/> </resultMap> <resultMap id="authorResult" type="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"/> </resultMap>

在上面的示例中你可以看到博客的作者關聯代表着“authorResult”結果映射來加載作者實例。

非常重要: 在嵌套據誒過映射中 id 元素扮演了非常重要的角色。應應該通常指定一個或多個屬性,它們可以用來唯一標識結果。實際上就是如果你離開她了,但是有一個嚴重的性能問題時 MyBatis 仍然可以工作。選擇的屬性越少越好,它們可以唯一地標識結果。主鍵就是一個顯而易見的選擇(儘管是聯合主鍵)。

現在,上面的示例用了外部的結果映射元素來映射關聯。這使得 Author 結果映射可以重用。然而,如果你不需要重用它的話,或者你僅僅引用你所有的結果映射合到一個單獨描述的結果映射中。你可以嵌套結果映射。這裏給出使用這種方式的相同示例:

<resultMap id="blogResult" type="Blog">   <id property="id" column="blog_id" />   <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"/>   </association> </resultMap>

What if the blog has a co-author? The select statement would look like:

<select id="selectBlog" parameterType="int" resultMap="blogResult">   select
    B.id            as blog_id,
    B.title         as blog_title,
    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,
    CA.id           as co_author_id,
    CA.username     as co_author_username,
    CA.password     as co_author_password,
    CA.email        as co_author_email,
    CA.bio          as co_author_bio
  from Blog B
  left outer join Author A on B.author_id = A.id
  left outer join Author CA on B.co_author_id = CA.id
  where B.id = #{id}</select>

Recall that the resultMap for Author is defined as follows.

<resultMap id="authorResult" type="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"/> </resultMap>

Because the column names in the results differ from the columns defined in the resultMap, you need to specify columnPrefix to reuse the resultMap for mapping co-author results.

<resultMap id="blogResult" type="Blog">   <id property="id" column="blog_id" />   <result property="title" column="blog_title"/>   <association property="author"     resultMap="authorResult" />   <association property="coAuthor"     resultMap="authorResult"     columnPrefix="co_" /> </resultMap>

上面你已經看到了如何處理“有一個”類型關聯。但是“有很多個”是怎樣的?下面這個部分就是來討論這個主題的。

集合

<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="blog_id" ofType="Post" select="selectPostsForBlog"/> </resultMap> <select id="selectBlog" parameterType="int" resultMap="blogResult">   SELECT * FROM BLOG WHERE ID = #{id}</select> <select id="selectPostsForBlog" parameterType="int" resultType="Blog">   SELECT * FROM POST WHERE BLOG_ID = #{id}</select>

這裏你應該注意很多東西,但大部分代碼和上面的關聯元素是非常相似的。首先,你應該注意我們使用的是集合元素。然後要注意那個新的“ofType”屬性。這個屬性用來區分 JavaBean(或字段)屬性類型和集合包含的類型來說是很重要的。所以你可以讀出下面這個映射:

<collection property="posts" javaType="ArrayList" column="blog_id" ofType="Post" select="selectPostsForBlog"/>

讀作: “在 Post 類型的 ArrayList 中的 posts 的集合。”

javaType 屬性是不需要的,因爲 MyBatis 在很多情況下會爲你算出來。所以你可以縮短寫法:

<collection property="posts" column="blog_id" ofType="Post" select="selectPostsForBlog"/>

集合的嵌套結果

至此,你可以猜測集合的嵌套結果是如何來工作的,因爲它和關聯完全相同,除了它應用了一個“ofType”屬性

First, let's look at the SQL:

<select id="selectBlog" parameterType="int" 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>

注意 這個對你所映射的內容沒有深度,廣度或關聯和集合相聯合的限制。當映射它們時你應該在大腦中保留它們的表現。你的應用在找到最佳方法前要一直進行的單元測試和性能測試。好在 myBatis 讓你後來可以改變想法,而不對你的代碼造成很小(或任何)影響。

高級關聯和集合映射是一個深度的主題。文檔只能給你介紹到這了。加上一點聯繫,你會很快清楚它們的用法。

鑑別器

<discriminator javaType="int" column="draft">   <case value="1" resultType="DraftPost"/> </discriminator>

有時一個單獨的數據庫查詢也許返回很多不同 (但是希望有些關聯) 數據類型的結果集。鑑別器元素就是被設計來處理這個情況的, 還有包括類的繼承層次結構。鑑別器非常容易理解,因爲它的表現很像 Java 語言中的 switch 語句。

定義鑑別器指定了 column 和 javaType 屬性。列是 MyBatis 查找比較值的地方。 JavaType 是需要被用來保證等價測試的合適類型(儘管字符串在很多情形下都會有用)。比如:

<resultMap id="vehicleResult" type="Vehicle">   <id property="id" column="id" />   <result property="vin" column="vin"/>   <result property="year" column="year"/>   <result property="make" column="make"/>   <result property="model" column="model"/>   <result property="color" column="color"/>   <discriminator javaType="int" column="vehicle_type">     <case value="1" resultMap="carResult"/>     <case value="2" resultMap="truckResult"/>     <case value="3" resultMap="vanResult"/>     <case value="4" resultMap="suvResult"/>   </discriminator> </resultMap>

在這個示例中, MyBatis 會從結果集中得到每條記錄, 然後比較它的 vehicle 類型的值。如果它匹配任何一個鑑別器的實例,那麼就使用這個實例指定的結果映射。換句話說,這樣做完全是剩餘的結果映射被忽略(除非它被擴展,這在第二個示例中討論) 。如果沒有任何一個實例相匹配,那麼 MyBatis 僅僅使用鑑別器塊外定義的結果映射。所以,如果 carResult 按如下聲明:

<resultMap id="carResult" type="Car">   <result property="doorCount" column="door_count" /> </resultMap>

那麼只有 doorCount 屬性會被加載。這步完成後完整地允許鑑別器實例的獨立組,儘管和父結果映射可能沒有什麼關係。這種情況下,我們當然知道 cars 和 vehicles 之間有關係, 如 Car 是一個 Vehicle 實例。因此,我們想要剩餘的屬性也被加載。我們設置的結果映射的簡單改變如下。

<resultMap id="carResult" type="Car" extends="vehicleResult">   <result property="doorCount" column="door_count" /> </resultMap>

現在 vehicleResult 和 carResult 的屬性都會被加載了。

儘管曾經有些人會發現這個外部映射定義會多少有一些令人厭煩之處。因此還有另外一種語法來做簡潔的映射風格。比如:

<resultMap id="vehicleResult" type="Vehicle">   <id property="id" column="id" />   <result property="vin" column="vin"/>   <result property="year" column="year"/>   <result property="make" column="make"/>   <result property="model" column="model"/>   <result property="color" column="color"/>   <discriminator javaType="int" column="vehicle_type">     <case value="1" resultType="carResult">       <result property="doorCount" column="door_count" />     </case>     <case value="2" resultType="truckResult">       <result property="boxSize" column="box_size" />       <result property="extendedCab" column="extended_cab" />     </case>     <case value="3" resultType="vanResult">       <result property="powerSlidingDoor" column="power_sliding_door" />     </case>     <case value="4" resultType="suvResult">       <result property="allWheelDrive" column="all_wheel_drive" />     </case>   </discriminator> </resultMap>

要記得 這些都是結果映射, 如果你不指定任何結果, 那麼 MyBatis 將會爲你自動匹配列和屬性。所以這些例子中的大部分是很冗長的,而其實是不需要的。也就是說,很多數據庫是很複雜的,我們不太可能對所有示例都能依靠它。

Auto-mapping

As you have already seen in the previous sections, in simple cases MyBatis can auto-map the results for you and in others you will need to build a result map. But as you will see in this section you can also mix both strategies. Let's have a deeper look at how auto-mapping works.

When auto-mapping results MyBatis will get the column name and look for a property with the same name ignoring case. That means that if a column named ID and property named id are found, MyBatis will set the id property with the ID column value.

Usually database columns are named using uppercase letters and underscores between words and java properties often follow the camelcase naming covention. To enable the auto-mapping between them set the setting mapUnderscoreToCamelCase to true.

Auto-mapping works even when there is an specific result map. When this happens, for each result map, all columns that are present in the ResultSet that have not a manual mapping will be auto-mapped, then manual mappings will be processed. In the following sample id and userName columns will be auto-mapped andhashed_password column will be mapped.

<select id="selectUsers" parameterType="int" resultType="User">   select
    user_id             as "id",
    user_name           as "userName",
    hashed_password
  from some_table
  where id = #{id}</select>
<resultMap id="userResultMap" type="User">   <result property="password" column="hashed_password"/> </resultMap>

There are three auto-mapping levels:

  • NONE - disables auto-mapping. Only manually mapped properties will be set.
  • PARTIAL - will auto-map results except those that have nested result mappings defined inside (joins).
  • FULL - auto-maps everything.

The default value is PARTIAL, and it is so for a reason. When FULL is used auto-mapping will be performed when processing join results and joins retrieve data of several different entities in the same row hence this may result in undesired mappings. To understand the risk have a look at the following sample:

<select id="selectBlog" parameterType="int" resultMap="blogResult">   select
    B.id,
    B.title,
    A.username,
  from Blog B left outer join Author A on B.author_id = A.id
  where B.id = #{id}</select>
<resultMap id="blogResult" type="Blog">   <association property="author" javaType="Author" resultMap="authorResult"/> </resultMap> <resultMap id="authorResult" type="Author">   <result property="username" column="author_username"/> </resultMap>

With this result map both Blog and Author will be auto-mapped. But note that Author has an id property and there is a column named id in the ResultSet so Author's id will be filled with Blog's id, and that is not what you were expecting. So use the FULL option with caution.

緩存

MyBatis 包含一個非常強大的查詢緩存特性,它可以非常方便地配置和定製。MyBatis 3 中的緩存實現的很多改進都已經實現了,使得它更加強大而且易於配置。

默認情況下是沒有開啓緩存的,除了局部的 session 緩存,可以增強變現而且處理循環依賴也是必須的。要開啓二級緩存,你需要在你的 SQL 映射文件中添加一行:

<cache/>

字面上看就是這樣。這個簡單語句的效果如下:

  • 映射語句文件中的所有 select 語句將會被緩存。
  • 映射語句文件中的所有 insert,update 和 delete 語句會刷新緩存。
  • 緩存會使用 Least Recently Used(LRU,最近最少使用的)算法來收回。
  • 根據時間表(比如 no Flush Interval,沒有刷新間隔), 緩存不會以任何時間順序 來刷新。
  • 緩存會存儲列表集合或對象(無論查詢方法返回什麼)的 1024 個引用。
  • 緩存會被視爲是 read/write(可讀/可寫)的緩存,意味着對象檢索不是共享的,而且可以安全地被調用者修改,而不干擾其他調用者或線程所做的潛在修改。

所有的這些屬性都可以通過緩存元素的屬性來修改。比如:

<cache   eviction="FIFO"   flushInterval="60000"   size="512"   readOnly="true"/>

這個更高級的配置創建了一個 FIFO 緩存,並每隔 60 秒刷新,存數結果對象或列表的 512 個引用,而且返回的對象被認爲是隻讀的,因此在不同線程中的調用者之間修改它們會導致衝突。

可用的收回策略有:

  • LRU – 最近最少使用的:移除最長時間不被使用的對象。
  • FIFO – 先進先出:按對象進入緩存的順序來移除它們。
  • SOFT – 軟引用:移除基於垃圾回收器狀態和軟引用規則的對象。
  • WEAK – 弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的對象。

默認的是 LRU。

flushInterval(刷新間隔)可以被設置爲任意的正整數,而且它們代表一個合理的毫秒形式的時間段。默認情況是不設置,也就是沒有刷新間隔,緩存僅僅調用語句時刷新。

size(引用數目)可以被設置爲任意正整數,要記住你緩存的對象數目和你運行環境的可用內存資源數目。默認值是 1024。

readOnly(只讀)屬性可以被設置爲 true 或 false。只讀的緩存會給所有調用者返回緩存對象的相同實例。因此這些對象不能被修改。這提供了很重要的性能優勢。可讀寫的緩存會返回緩存對象的拷貝(通過序列化) 。這會慢一些,但是安全,因此默認是 false。

使用自定義緩存

除了這些自定義緩存的方式, 你也可以通過實現你自己的緩存或爲其他第三方緩存方案創建適配器來完全覆蓋緩存行爲。

<cache type="com.domain.something.MyCustomCache"/>

這個示 例展 示了 如何 使用 一個 自定義 的緩 存實 現。type 屬 性指 定的 類必 須實現 org.mybatis.cache.Cache 接口。這個接口是 MyBatis 框架中很多複雜的接口之一,但是簡單給定它做什麼就行。

public interface Cache {   String getId();   int getSize();   void putObject(Object key, Object value);   Object getObject(Object key);   boolean hasKey(Object key);   Object removeObject(Object key);   void clear();   ReadWriteLock getReadWriteLock(); }

要配置你的緩存, 簡單和公有的 JavaBeans 屬性來配置你的緩存實現, 而且是通過 cache 元素來傳遞屬性, 比如, 下面代碼會在你的緩存實現中調用一個稱爲 “setCacheFile(String file)” 的方法:

<cache type="com.domain.something.MyCustomCache">   <property name="cacheFile" value="/tmp/my-custom-cache.tmp"/> </cache>

你可以使用所有簡單類型作爲 JavaBeans 的屬性,MyBatis 會進行轉換。

記得緩存配置和緩存實例是綁定在 SQL 映射文件的命名空間是很重要的。因此,所有在相同命名空間的語句正如綁定的緩存一樣。語句可以修改和緩存交互的方式, 或在語句的語句的基礎上使用兩種簡單的屬性來完全排除它們。默認情況下,語句可以這樣來配置:

<select ... flushCache="false" useCache="true"/> <insert ... flushCache="true"/> <update ... flushCache="true"/> <delete ... flushCache="true"/>

因爲那些是默認的,你明顯不能明確地以這種方式來配置一條語句。相反,如果你想改變默認的行爲,只能設置 flushCache 和 useCache 屬性。比如,在一些情況下你也許想排除從緩存中查詢特定語句結果,或者你也許想要一個查詢語句來刷新緩存。相似地,你也許有一些更新語句依靠執行而不需要刷新緩存。

參照緩存

回想一下上一節內容, 這個特殊命名空間的唯一緩存會被使用或者刷新相同命名空間內的語句。也許將來的某個時候,你會想在命名空間中共享相同的緩存配置和實例。在這樣的情況下你可以使用 cache-ref 元素來引用另外一個緩存。

<cache-ref namespace="com.someone.application.data.SomeMapper"/>
發佈了4 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章