MyBatis中resultMap的相關介紹

resultMap 元素是 MyBatis 中最重要最強大的元素。它就是讓你遠離從結果集中取出數據的JDBC 代碼的那個東西,並且在一些情形下容許你作一些JDBC不支持的事情。ResultMap 的設計就是對於一些簡單的語句咱們不須要明確它們的結果映射,可是到於複雜的語句確實須要描述它們的關係。  java

  1. 簡單結果映射


    對於一個普通的JavaBean:
  2. 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;
        
    }
    }




  3. 基於 JavaBean 的規範,上面這個類有 3 個屬性:id,username 和 hashedPassword。這些 在 select 語句中會精確匹配到列名。 這樣的一個 JavaBean 能夠被映射到結果集 :


  4. <select id=」selectUsers」 parameterType=」int」 resultType=」com.someapp.model.User」>
        
    select id, username, hashedPassword
        
    from some_table
        
    where id = #{id}
    </select>




  5. 這些狀況下,MyBatis 會在幕後自動建立一個 ResultMap,基於屬性名來映射列到JavaBean 的屬性上。若是列名沒有精確匹配,你能夠在列名上使用 select 字句的別名(一個基本的SQL特性)來匹配標籤。好比: 



     
  6. <select id=」selectUsers」 parameterType=」int」 resultType=」com.someapp.model.User」>
        
    select 
        
    user_id as id, 
        
    user_name as username, 
        
    hashed_Password as hashedPassword
        
    from some_table
        
    where id = #{id}
    </select>




  7. 還能夠經過下面的這種方式來解決列名和屬性名不一致的狀況:
     
  8. <resultMap id="userResultMap" type="User">
        
    <id property="id" column="user_id" />
        
    <result property="username" column="user_name"/>
        
    <result property="hashedPassword" column="hashed_password"/>
    </resultMap>
    引用它的語句使用 resultMap 屬性就好了(注意咱們去掉了resultType 屬性,這兩個屬性只能包含其中的一個)
    <select id=」selectUsers」 parameterType=」int」 resultMap=」userResultMap」>
        
    select id, username, hashedPassword
        
    from some_table
        
    where id = #{id}
    </select>            






  9. 2.高級結果映射 數據庫

    對於下面的這個語句子咱們如何進行映射呢? 編程

    <!-- Very Complex Statement --> 緩存

     

    <select id="selectBlogDetails" parameterType="int" resultMap="detail edBl ogRes ultMa p"> app

        select dom

        B.id as blog_id, post

        B.title as blog_title, 性能

        B.author_id as blog_author_id, this

        A.id as author_id, spa

        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" column="blog_author_id" 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" column="post_author_id" javaType="Author" />

        <collection property="comments" column="post_id" ofType=" Comment">

            <id property="id" column="comment_id"/>

        </collection >

        <collection property="tags" column="post_id" 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 – 基於某些值的結果映射
           嵌入結果映射 – 這種情形結果也映射它自己,所以能夠包含不少相同的元素,或者它能夠參照一個外部的結果映射。

    2.1 id,result 

     id 和 result 都映射一個單獨列的值到簡單數據類型(字符串,整型,雙精度浮點數,日期等)的單獨屬性或字段。這二者之間的惟一不一樣是 id 表示的結果將是當比較對象實例時用到的標識屬性。這幫助來改進總體表現,特別是緩存和嵌入結果映射(也就是聯合映射)。 每一個都有一些屬性: 

     

     

    屬性

    描述

    property

    映射到列結果的字段或屬性。若是匹配的是存在的, 和給定名稱相同的JavaBeans 的屬性,那麼就會使用。不然 MyBatis 將會尋找給定名稱的字段。這兩種情形你可使用一般點式的複雜屬性導航。好比,你能夠這樣映射一些東西:「username」,或者映射到一些複雜的東西: 「address.street.number」。

    column

    從數據庫中獲得的列名 ,或者是列名的重命名標籤。 這也是一般和會傳遞給 resultSet.getString(columnName)方法參數中相同的字符串。

    javaType

    一個 Java 類的徹底限定名,或一個類型別名(參加上面內建類型別名 的列表)。若是你映射到一個 JavaBean,MyBatis 一般能夠判定類型。 然而,若是你映射到的是 HashMap,那麼你應該明確地指定 javaType 來保證所需的行爲。

    jdbcType

    在這個表格以後的所支持的 JDBC 類型列表中的類型。JDBC 類型是僅 僅須要對插入,更新和刪除操做可能爲空的列進行處理。這是 JDBC 的須要,而不是 MyBatis 的。若是你直接使用 JDBC 編程,你須要指定 這個類型-但僅僅對可能爲空的值。

    typeHandler

    使用這個屬性 ,你能夠覆蓋默認的類型處理器。這個屬性值是類的徹底限定名或者 是一個類型處理器的實現,或者是類型別名。

    2.2構造方法

    <constructor >
          <idArg column="id" javaType="int"/>       

          <arg column=」username」 javaType=」String」/>

    </constructor> 

    看看下面這個構造方法:

    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 元素是相同的。 

     2.3 關聯

    <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

    映射到列結果的字段或屬性。若是匹配的是存在的,和給定名稱相同的 JavaBeans 的屬性,那麼就會使用。不然 MyBatis 將會尋找給定名稱的字段。 這兩種情形你可使用一般點式的復 雜屬性導航。好比,你能夠 這樣映射 一 些 東 西 :「 username 」, 或 者 映 射 到 一 些 復 雜 的 東 西 : 「address.street.number」。

    column

    來自數據庫的類名,或重命名的列標籤。這和一般傳遞給 resultSet.getString(columnName)方法的字符串是相同的。 注意:要處理複合主鍵,你能夠指定多個列名經過 column=」 {prop1=col1,prop2=col2}」這種語法來傳遞給嵌套查詢語句。這會引發 prop1 和 prop2 以參數對象形式來設置給目標嵌套查詢語句。

    javaType

    一個 Java 類的徹底限定名,或一個類型別名(參加上面內建類型別名的列 表)。若是你映射到一個 JavaBean,MyBatis 一般能夠判定類型。然而,如 果你映射到的是 HashMap,那麼你應該明確地指定 javaType 來保證所需的 行爲。

    jdbcType

    在這個表格以前的所支持的 JDBC 類型列表中的類型。JDBC 類型是僅僅 須要對插入,更新和刪除操做可能爲空的列進行處理。這是 JDBC 的須要, 而不是 MyBatis 的。若是你直接使用 JDBC 編程,你須要指定這個類型-但 僅僅對可能爲空的值。

    typeHandler

    咱們在前面討論過默認的類型處理器 。使用這個屬性,你能夠覆 蓋默認的 類型處理器。這個屬性值是類的徹底限定名或者是一個類型處理器的實現, 或者是類型別名。

    關聯的嵌套查詢

     

    select

    另一個映射語句的 ID,能夠加載這個屬性映射須要的複雜類型。獲取的 在列屬性中指定的列的值將被傳遞給目標 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 查詢問題」。 

    因此還有另一種方法。

    關聯的嵌套結果 

     

    resultMap

    這是結果映射的ID,能夠映射關聯的嵌套結果到一個合適的對象圖中。這是一種替代方法來調用另一個查詢語句。這容許你聯合多個表 來合成到一個單獨的結果集。這樣的結果集可能包含重複,數據的重複組須要被分解,合理映射到一個嵌套的對象圖。爲了使它變得容易,MyBatis 讓你「連接」結果映射,來處理嵌套結果。

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

    <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=」blog_id」 column="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>

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

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

    <resultMap id="blogResult" type="Blog">

        <id property=」blog_id」 column="id" />

        <result property="title" column="blog_title"/>

        <association property="author" column="blog_author_id" 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>

    2.4集合

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

         SELECT * FROM POST WHERE BLOG_ID = #{id}

    </select>

     

    這裏你應該注意不少東西,但大部分代碼和上面的關聯元素是很是類似的。首先,你應 該注意咱們 使用的是 集合元素 。而後要 注意那個 新的「of Ty pe 」屬性。這 個屬性用 來區分 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 」屬性

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

     

    一樣,若是你引用更長的形式容許你的結果映射的更多重用,你可使用下面這個替代的映射:

    <resultMap id="blogResult" type="Blog">

        <id property=」id」 column="blog_id" />

        <result property="title" column="blog_title"/>

        <collection property="posts" ofType="Post" resultMap=」blogPostResult」/>

    </resultMap>

    <resultMap id="blogPostResult" type="Post">

        <id property="id" column="post_id"/>

        <result property="subject" column="post_subject"/>

        <result property="body" column="post_body"/>

    </resultMap>

相關文章
相關標籤/搜索