zoukankan      html  css  js  c++  java
  • 【MyBatis】学习笔记011--resultMap高级结果映射之多对一、一对多

    MyBatis 创建时的一个思想是:数据库不可能永远是你所想或所需的那个样子。 我们希望每个数据库都具备良好的第三范式或 BCNF 范式,可惜它们并不都是那样。 如果能有一种数据库映射模式,完美适配所有的应用程序,那就太好了,但可惜也没有。 而 ResultMap 就是 MyBatis 对这个问题的答案。

    现实中,我们可能会遇到很多极为复杂的查询需求,像查询关系中的多对一、一对多,SQL语句好写,在后台逻辑中,如何去存储它们,可能没有那么容易做到,MyBatis的出现,为我们解决了这一问题。下面我们就来看如何做到理想中的查询。

    前提

    假设我们拥有两张表blog(博客表)、author(作者表)

    bolg
    字段 bolg_id bolg_title author_id
    author
    字段 author_id author_username

    同时,我们的实体类如下

    public Blog{
      private int blog_id;
      private String blog_title;
      private Author author;  
    }
    public Author{
      private int author_id;
    private String author_name;
    private List<Blog> blogs; }

    需求1--多对一

    需求:查询bolg及其作者author

    1.1 方式一

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

    就是这么简单。我们有两个 select 查询语句:一个用来加载博客(Blog),另外一个用来加载作者(Author),而且博客的结果映射描述了应该使用 selectAuthor 语句加载它的 author 属性。

    其它所有的属性将会被自动加载,只要它们的列名和属性名相匹配。

    这种方式虽然很简单,但在大型数据集或大型数据表上表现不佳。这个问题被称为“N+1 查询问题”。 概括地讲,N+1 查询问题是这样子的:

    • 你执行了一个单独的 SQL 语句来获取结果的一个列表(就是“+1”)。
    • 对列表返回的每条记录,你执行一个 select 查询语句来为每条记录加载详细信息(就是“N”)。

    这个问题会导致成百上千的 SQL 语句被执行。有时候,我们不希望产生这样的后果。

    好消息是,MyBatis 能够对这样的查询进行延迟加载,因此可以将大量语句同时运行的开销分散开来。 然而,如果你加载记录列表之后立刻就遍历列表以获取嵌套的数据,就会触发所有的延迟加载查询,性能可能会变得很糟糕。

    所以还有另外一种方法。

    1.2 方式二

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

    以上是使用 2个resultMap+1个select标签完成的,如果觉得繁琐、混乱,可简化成如下方式

    <select id="selectBlog" resultMap="blogResult">
      select
        B.blog_id            as blog_id,
        B.blog_title         as blog_title,
        B.author_id     as blog_author_id,
        A.author_id            as author_id,
        A.author_username      as author_username,
      from Blog B left outer join Author A on B.author_id = A.author_id
      where B.id = #{id}
    </select>
    
    <resultMap id="blogResult" type="Blog">
      <id property="blog_id" column="blog_id" />
      <result property="blog_title" column="blog_title"/>
      <association property="author" javaType="Author">
        <id property="author_id" column="author_id"/>
        <result property="author_username" column="author_username"/>
      </association>
    </resultMap>

    需求2--一对多

    需求:查询作者author及其所有博客

    类似于需求1,一对多也有两种方式

    2.1 方式1

    <select id="selectAuthor" resultMap="authorResult" parameterType="Integer">
      select * from author where author_id = #{id}
    </select>
    <select id="selectBlog" parameterType="Integer" resultType="Blog">
      select * from blog where author_id = #{id}
    </select>
    
    <resultMap id="authorResult" type="author">
      <id property="author_id" column="author_id" />
      <result property="author_name" column="author_name" />
      <collection property="blogs" javaType="ArrayList" ofType="Blog" column="author_id" select="selectBlog"/>
    </resultMap>

    2.2 方式2

    <select id="selectAuthor" resultMap="authorResult" parameterType="Integer">
      select A.author_id as authorId, A.author_username as authorUserName,B.blog_id as blogId,B.blog_title as blogTitle
      from blog as B,author as A
    on A.author_id = B.author_id where A.author_id = #{id}
    </select> <resultMap id="authorResult" type="Author"> <id property="author_id" column="authorId"/> <result property="author_name" column="authorUserName"/> <collection property="blogs" ofType="Blog" /> <id property="blog_id" column="blogId"/> <result property="blog_title" column="blogTitle"/> </collection> </resultMap>

    同样的,推荐使用方式2.

     总结

  • 相关阅读:
    594 One Little, Two Little, Three Little Endians
    提出js框
    从4个细节做好查询语句优化
    Windows Sever2008 R2 iis部署
    收集 常用CSS样式的笔记
    html常用标签介绍
    加密URL
    JQuery UI选项卡插件及图片轮播插件
    推荐两款富文本编辑器:NicEdit和Kindeditor
    合并一条SQL语句 根据不同条件
  • 原文地址:https://www.cnblogs.com/AirCL/p/14340662.html
Copyright © 2011-2022 走看看