Mybatis的ResultMap的使用

  本篇文章經過一個實際工做中遇到的例子開始吧:前端

  工程使用Spring+Mybatis+Mysql開發。具體的業務邏輯很重,對象之間一層一層的嵌套。和數據庫表對應的是大量的model類,而和前端交互的是Vo類。如今須要作一個需求,有兩種方式來實現:java

  •   使用現有的Service接口,或者本身在編寫一些用到的接口,手動使用Java代碼來分別調用Service接口來查出各個model,而後在業務層將model轉換爲vo,最後返回給前端json串。
  •       爲需求相關的頁面定義本身的vo,在vo中只定義前端用到的字段。而不是像第一種方式同樣vo中一層一層的嵌套model。而後使用sql語句進行表關聯,查詢用到的字段。組裝爲vo直接返回

  例子到此結束,我想這兩種完成方法大部分Java程序員都遇到過。兩種方式都行得通,可是在項目的技術選型(Spring+Mybatis+Mysql)下面,哪一種跟好呢?程序員

  個人我的經驗是若是業務邏輯不是太複雜,兩種無所謂。可是若是業務邏輯太複雜,vo各類嵌套model和vo的話,我很是強烈的推薦第二種。(其實第二中可能hibernate更加適合,可是在此處不考慮),在筆者的此次需求中,使用第一中方式查詢速度爲5s,而改成第二種方式以後查詢速度爲60ms。提高的太快了。sql

  PS:上面的數字僅供參考,沒太多實際意義,由於這個與具體代碼的編寫有關。數據庫

      好了,言歸正傳。咱們來講說第二種中的使用的Mybatis的ResultMap的使用。編程

  

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

你已經看到簡單映射語句的示例了,但沒有明確的 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:mybatis

  

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 語句中會精確匹配到列名。app

這樣的一個 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 – 基於某些值的結果映射
      • 嵌入結果映射 – 這種情形結果也映射它自己,所以能夠包含不少相 同的元素,或者它能夠參照一個外部的結果映射。
ResultMap Attributes
Attribute Description
id A unique identifier in this namespace that can be used to reference this result map.
type A fully qualified Java class name, or a type alias (see the table above for the list of built-in type aliases).
autoMapping If present, MyBatis will enable or disable the automapping for this ResultMap. This attribute overrides the global autoMappingBehavior. Default: 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 咱們在前面討論過默認的類型處理器。使用這個屬性,你能夠覆蓋默 認的類型處理器。這個屬性值是類的徹底限定名或者是一個類型處理 器的實現,或者是類型別名。

支持的 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>

  

關聯

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

關聯的嵌套查詢

屬性 描述
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="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.
notNullColumn By default a child object is created only if at least one of the columns mapped to the child's properties is non null. With this attribute you can change this behaviour by specifiying which columns must have a value so MyBatis will create a child object only if any of those columns is not null. Multiple column names can be specified using a comma as a separator. Default value: unset.

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

 

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

  上面你已經看到了如何處理「有一個」類型關聯。可是「有不少個」是怎樣的?下面這 個部分就是來討論這個主題的。

集合

<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" 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="id" ofType="Post" select="selectPostsForBlog"/>

  

讀做: 「在 Post 類型的 ArrayList 中的 posts 的集合。」

javaType 屬性是不須要的,由於 MyBatis 在不少狀況下會爲你算出來。因此你能夠縮短 寫法:

<collection property="posts" column="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 將會爲你自動匹配列 和屬性。因此這些例子中的大部分是很冗長的,而實際上是不須要的。也就是說,不少數據庫 是很複雜的,咱們不太可能對全部示例都能依靠它。

相關文章
相關標籤/搜索