MyBatis 關聯(association)和集合(collection)

關聯(association)

<association property="author" column="blog_author_id" javaType="Author">
    <id property="id" column="author_id"/>
    <result property="username" column="author_username"/>
</association>
  • 嵌套查詢,經過執行另一個SQL映射語句來返回預期的複雜類型
  • 嵌套結果,使用嵌套結果映射來處理重複的聯合結果的子集。

關聯的嵌套查詢

<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屬性值。java

這種方式很簡單,可是對於大型數據集合和列表將不會表現很好。問題就是咱們所熟知的「N+1」查詢問題:dom

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

這個問題會致使成百上千的SQL語句被執行,不是所指望的。post

關聯的嵌套結果

<resultMap id="blogResult" type="Blog">
    <id property="id" column="blog_id" jdbcType="BIGINT" />
    <result property="title" column="blog_title" jdbcType="VARCHAR" />
    <association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult" />
</resultMap>

<resultMap id="authorResult" type="Author">
    <id property="id" column="author_id" jdbcType="BIGINT" />
    <result property="username" column="author_username" jdbcType="VARCHAR" />
    <result property="email" column="author_email" jdbcType="VARCHAR" />
    <result property="bio" column="author_bio" jdbcType="VARCHAR" />
</resultMap>

<select id="selectBlog" 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.email as author_email,
        a.bio as author_bio
    from
        Blog B left outer join Author a on a.id = B.author_id
    where
        B.id = #{id}
</select>

上面的示例中,博客的做者關聯表明着「authorResult」結果映射來加載做者實例。性能

很是重要: id元素在嵌套結果映射中扮演着很是重要的角色。你應該老是指定一個或多個能夠惟一標識結果的屬性。實際上若是不指定它的話,MyBatis仍然能夠工做,可是會有嚴重的性能問題。code

上面的示例中,使用了外部的結果嵌套來映射關聯。這使得Author結果映射能夠重用。然而,若是不須要重用它的話,你能夠嵌套結果映射。以下示例:blog

<resultMap id="blogResult" type="Blog">
    <id property="id" column="blog_id" jdbcType="BIGINT" />
    <result property="title" column="blog_title" jdbcType="VARCHAR" />
    <association property="author"  javaType="Author" jdbcType="BIGINT">
        <id property="id" column="author_id" />
        <result property="username" column="author_username" jdbcType="VARCHAR" />
        <result property="email" column="author_email" jdbcType="VARCHAR" />
        <result property="bio" column="author_bio" jdbcType="VARCHAR" />
    </assoaction>
</resultMap>

集合

上面是如何處理「有一個」類型關聯。可是對於「有多個」,需藉助集合來關聯。ci

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

集合元素的做用幾乎和關聯是相同的。繼續上面的示例,一個博客只有一個做者。可是博客有不少文章。在JavaBean的博客Blog類中,能夠用下面的示例來表述:博客

private List<Post> posts;

集合的嵌套查詢

<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" />
    <collection property="posts" column="id" javaType="ArrayList" ofType="Post" select="selectPosts4Blog" />
</resultMap>

<select id="selectBlog" resultMap="blogResult">
    select * from blog where id=#{id}
</select>

<select id="selectPosts4Blog" resultType="Post">
    select * from post where blog_id = #{id}
</select>

注意ofType屬性,用來區分JavaBean屬性類型和集合包含的類型。it

<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPosts4Blog" />

javaType屬性不是必需的,由於MyBatis在不少狀況下會自動計算出來。io

集合的嵌套結果

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

<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 join post p on p.blog_id = b.id
    where id = #{id}
</select>
相關文章
相關標籤/搜索