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>
相关文章
相关标签/搜索