之前我们提到的映射,都是简单的字段和对象属性一对一,假设对象的属性也是一个对象,即涉及到两个表的关联,此时应该如何进行映射处理?

先看两张表,author 和 book:
  

业务上对应关系为,一个作者能写多本书,但是一本书只有一个作者。对应的Java类如下:
public class Book {
private long id;
private String name;
private int price;
private Author author; //... getter and setter
}
8
 
1
public class Book {
2
    private long id;
3
    private String name;
4
    private int price;
5
    private Author author;
6

7
    //... getter and setter
8
}
public class Author {
private long id;
private String name;
private int age;
private List<Book> bookList; //... getter and setter
}
8
 
1
public class Author {
2
    private long id;
3
    private String name;
4
    private int age;
5
    private List<Book> bookList;
6
    
7
    //... getter and setter
8
}

1、association 关联

现在我们希望通过查询得到一个Book类,且该类中的author属性要求同时获取出来,这时候已经不是简单的数据库字段和对象属性的一对一映射,而涉及到两张表,此时我们就要用到 association 关键字。

association 表示一个复杂类型的关联,可以将许多结果包装成这种类型。它是 resultMap 中的标签属性,这意味着当你需要使用嵌套查询返回结果,那么你的结果映射只能选择 resultMap,而不能再使用 resultType。

1.1 method1

使用起来和resultMap的基本结构无异,所以如上我们提到的查询需求,在mapper中可以这样写:
<mapper namespace="dulk.learn.mybatis.dao.BookDao">

    <resultMap id="bookResultMap" type="dulk.learn.mybatis.pojo.Book">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="price" column="price" />
<!--关联属性-->
<association property="author" javaType="dulk.learn.mybatis.pojo.Author">
<!--注:此处column应为book中外键列名-->
<id property="id" column="author_id" />
<!--注:避免属性重名,否则属性值注入错误-->
<result property="name" column="authorName" />
<result property="age" column="authorAge" />
</association>
</resultMap> <!--嵌套查询,结果映射只能使用resultMap-->
<select id="findBookById" parameterType="long" resultMap="bookResultMap">
SELECT
b.*,
a.name AS 'authorName',
a.age AS 'authorAge'
FROM book b, author a
WHERE b.author_id = a.id
AND b.id = #{id}
</select> </mapper>
28
 
1
<mapper namespace="dulk.learn.mybatis.dao.BookDao">
2

3
    <resultMap id="bookResultMap" type="dulk.learn.mybatis.pojo.Book">
4
        <id property="id" column="id" />
5
        <result property="name" column="name" />
6
        <result property="price" column="price" />
7
        <!--关联属性-->
8
        <association property="author" javaType="dulk.learn.mybatis.pojo.Author">
9
            <!--注:此处column应为book中外键列名-->
10
            <id property="id" column="author_id" />
11
            <!--注:避免属性重名,否则属性值注入错误-->
12
            <result property="name" column="authorName" />
13
            <result property="age" column="authorAge" />
14
        </association>
15
    </resultMap>
16

17
    <!--嵌套查询,结果映射只能使用resultMap-->
18
    <select id="findBookById" parameterType="long" resultMap="bookResultMap">
19
        SELECT
20
            b.*,
21
            a.name AS 'authorName',
22
            a.age  AS 'authorAge'
23
        FROM book b, author a
24
        WHERE b.author_id = a.id
25
        AND b.id = #{id}
26
    </select>
27
    
28
</mapper>

可以看到 association 最基本的两个属性:
  • property - 关联对象在类中的属性名(即Author在Book类中的属性名,author)
  • javaType - 关联对象的Java类型

而association中的结构,则和resultMap无异了,同样是id和result,但是仍然有两个需要注意的点:
  • id中的column属性,其值应该尽量使用外键列名,主要是对于重名的处理,避免映射错误
  • 同样的,对于result中的column属性的值,也要避免重名带来的映射错误,如上例若 a.name 不采用别名 "authorName",则会错误地将 b.name 赋值给Author的name属性

1.2 method2

之前有提到,说 association 中结构和resultMap无异,事实上我们也可以直接引用其他的resultMap,如下(注意修改id别名):
<mapper namespace="dulk.learn.mybatis.dao.BookDao">

    <!--author的resultMap-->
<resultMap id="authorResultMap" type="dulk.learn.mybatis.pojo.Author">
<id property="id" column="authorId"/>
<result property="name" column="authorName"/>
<result property="age" column="authorAge"/>
</resultMap> <resultMap id="bookResultMap" type="dulk.learn.mybatis.pojo.Book">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="price" column="price"/>
<!--引用author的resultMap-->
<association property="author" resultMap="authorResultMap" />
</resultMap> <!--注意这里a.id的别名和authorResultMap中相对应-->
<select id="findBookById" parameterType="long" resultMap="bookResultMap">
SELECT
b.*,
a.id AS 'authorId',
a.name AS 'authorName',
a.age AS 'authorAge'
FROM book b, author a
WHERE b.author_id = a.id
AND b.id = #{id}
</select>
</mapper>
29
 
1
<mapper namespace="dulk.learn.mybatis.dao.BookDao">
2

3
    <!--author的resultMap-->
4
    <resultMap id="authorResultMap" type="dulk.learn.mybatis.pojo.Author">
5
        <id property="id" column="authorId"/>
6
        <result property="name" column="authorName"/>
7
        <result property="age" column="authorAge"/>
8
    </resultMap>
9

10
    <resultMap id="bookResultMap" type="dulk.learn.mybatis.pojo.Book">
11
        <id property="id" column="id"/>
12
        <result property="name" column="name"/>
13
        <result property="price" column="price"/>
14
        <!--引用author的resultMap-->
15
        <association property="author" resultMap="authorResultMap" />
16
    </resultMap>
17

18
    <!--注意这里a.id的别名和authorResultMap中相对应-->
19
    <select id="findBookById" parameterType="long" resultMap="bookResultMap">
20
        SELECT
21
            b.*,
22
            a.id   AS 'authorId',
23
            a.name AS 'authorName',
24
            a.age  AS 'authorAge'
25
        FROM book b, author a
26
        WHERE b.author_id = a.id
27
        AND b.id = #{id}
28
    </select>
29
</mapper>

1.3 method3

最后,还有一种方式,就是我们先查询出author,再将其放到book中去,相当于查询语句分为两次,只是最终结果交给MyBatis来帮我们组装,这种方式利用了 association 的 select 属性,同时还需要另写 author 的查询sql,book 的查询sql也可以不用再联表。这种方式相当于两次查询,性能和效率较低,并不提倡。如上例使用这样的方式,则如下:
<mapper namespace="dulk.learn.mybatis.dao.BookDao">

    <resultMap id="bookResultMap" type="dulk.learn.mybatis.pojo.Book">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="price" column="price"/>
<!--使用select属性进行查询关联-->
<association property="author" column="author_id" javaType="dulk.learn.mybatis.pojo.Author" select="findAuthorById"/>
</resultMap> <!--简化了book的查询语句,不再需要与其他表关联-->
<select id="findBookById" parameterType="long" resultMap="bookResultMap">
SELECT b.*
FROM book b
WHERE b.id = #{id}
</select> <!--新增了author表的查询语句,将会被调用获取结果并组装给book-->
<select id="findAuthorById" parameterType="long" resultType="dulk.learn.mybatis.pojo.Author">
SELECT *
FROM author
WHERE id = #{id}
</select> </mapper>
25
 
1
<mapper namespace="dulk.learn.mybatis.dao.BookDao">
2

3
    <resultMap id="bookResultMap" type="dulk.learn.mybatis.pojo.Book">
4
        <id property="id" column="id"/>
5
        <result property="name" column="name"/>
6
        <result property="price" column="price"/>
7
        <!--使用select属性进行查询关联-->
8
        <association property="author" column="author_id" javaType="dulk.learn.mybatis.pojo.Author" select="findAuthorById"/>
9
    </resultMap>
10

11
    <!--简化了book的查询语句,不再需要与其他表关联-->
12
    <select id="findBookById" parameterType="long" resultMap="bookResultMap">
13
        SELECT b.*
14
        FROM book b
15
        WHERE b.id = #{id}
16
    </select>
17

18
    <!--新增了author表的查询语句,将会被调用获取结果并组装给book-->
19
    <select id="findAuthorById" parameterType="long" resultType="dulk.learn.mybatis.pojo.Author">
20
        SELECT *
21
        FROM author
22
        WHERE id = #{id}
23
    </select>
24

25
</mapper>

2、collection 集合

有了对 association 的认识,使用 collection 其实也就无非是依葫芦画瓢了,同样只能是 resultMap,同样需要注意列名重复的问题,同样可以引用resultMap或者使用select。下面索性直接看个例子吧,即获取一个Author作者,其中包含属性 List<Book>:
<mapper namespace="dulk.learn.mybatis.dao.AuthorDao">

    <resultMap id="authorResultMap" type="dulk.learn.mybatis.pojo.Author">
<id property="id" column="id"/>
<result property="name" column="name" />
<result property="age" column="age" />
<!--使用collection属性,ofType为集合内元素的类型-->
<collection property="bookList" ofType="dulk.learn.mybatis.pojo.Book" columnPrefix="book_">
<id property="id" column="id"/>
<result property="name" column="name" />
<result property="price" column="price" />
</collection>
</resultMap> <select id="findById" parameterType="long" resultMap="authorResultMap">
SELECT a.*, b.id AS 'book_id', b.name AS 'book_name', b.price AS 'book_price'
FROM author a, book b
WHERE a.id = b.author_id
AND a.id = #{authorId}
</select> </mapper>
22
 
1
<mapper namespace="dulk.learn.mybatis.dao.AuthorDao">
2

3
    <resultMap id="authorResultMap" type="dulk.learn.mybatis.pojo.Author">
4
        <id property="id" column="id"/>
5
        <result property="name" column="name" />
6
        <result property="age" column="age" />
7
        <!--使用collection属性,ofType为集合内元素的类型-->
8
        <collection property="bookList" ofType="dulk.learn.mybatis.pojo.Book" columnPrefix="book_">
9
            <id property="id" column="id"/>
10
            <result property="name" column="name" />
11
            <result property="price" column="price" />
12
        </collection>
13
    </resultMap>
14

15
    <select id="findById" parameterType="long" resultMap="authorResultMap">
16
        SELECT a.*, b.id AS 'book_id', b.name AS 'book_name', b.price AS 'book_price'
17
        FROM author a, book b
18
        WHERE a.id = b.author_id
19
        AND a.id = #{authorId}
20
    </select>
21

22
</mapper>

另外延伸一下关于避免字段重名的方式,如上例 select 中,列名的别名都增加了前缀 "book_",那么在collection中进行映射描时,就有两种方式:
  • 第一种即 column 的值和列名完全一致,如 column="book_id"
  • 第二种也就是推荐的方式,在 collection 中使用属性 columnPrefix 来定义统一前缀,在接下来的 column 中就可以减少工作量了,如上例中 columnPrefix = "book_",column = "id",它们的效果等同于 column = "book_id"


[04] 高级映射 association和collection的更多相关文章

  1. mybatis入门基础(六)----高级映射(一对一,一对多,多对多)

    一:订单商品数据模型 1.数据库执行脚本 创建数据库表代码: CREATE TABLE items ( id INT NOT NULL AUTO_INCREMENT, itemsname ) NOT ...

  2. 【Mybatis高级映射】一对一映射、一对多映射、多对多映射

    前言 当我们学习heribnate的时候,也就是SSH框架的网上商城的时候,我们就学习过它对应的高级映射,一对一映射,一对多映射,多对多映射.对于SSM的Mybatis来说,肯定也是差不多的.既然开了 ...

  3. MyBatis学习--高级映射

    简介 前面说过了简单的数据库查询和管理查询,在开发需求中有一些一对一.一对多和多对多的需求开发,如在开发购物车的时候,订单和用户是一对一,用户和订单是一对多,用户和商品是多对多.这些在Hibernat ...

  4. Mybatis学习记录(六)----Mybatis的高级映射

    1.一对多查询 1.1 需求 查询订单及订单明细的信息. 1.2 sql语句 确定主查询表:订单表 确定关联查询表:订单明细表 在一对一查询基础上添加订单明细表关联即可. SELECT orders. ...

  5. 六 mybatis高级映射(一对一,一对多,多对多)

    1  订单商品数据模型 以订单商品数据为模型,来对mybaits高级关系映射进行学习.

  6. Mybatis(四) 高级映射,一对一,一对多,多对多映射

    天气甚好,怎能不学习? 一.单向和双向 包括一对一,一对多,多对多这三种情况,但是每一种又分为单向和双向,在hibernate中我们就详细解析过这单向和双向是啥意思,在这里,在重复一遍,就拿一对多这种 ...

  7. 高级映射,查询缓存和与spring整合

    一.高级映射 -------一对一 这里以订单查询为例,其中有一个外键为user_id,通过这个关联用户表.这里要实现的功能是这个两个表关联查询,得到订单的信息和部分user的信息.order表结构如 ...

  8. javaMybatis映射属性,高级映射

    映射文件的sql属性: id:标识符(一般都是dao层方法名) resultType:sql返回类型 resultMap:放回的映射类型 parameterType:参数类型 useGenerated ...

  9. mybatis高级映射(一对一,一对多)

    mybatis高级映射 一对一关联映射 需求:查询订单信息,关联查询用户信息(一个订单对应一个用户) (1)通过resultType实现 sql语句: select orders.* , USER.u ...

随机推荐

  1. The open source JavaScript graphing library that powers Plotly

    https://plot.ly/javascript/time-series/ https://plot.ly/javascript/ https://github.com/plotly/plotly ...

  2. c3p0死锁

    1.APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks! 抛出以下异常信息: com.mchang ...

  3. LoadRunner11录制脚本出现的问题

    问题一:无法启动IE浏览器 原因:设置录制程序的录制填写错误,因为IE有两个一个是32位的一个是64位的 我们需要设置浏览器为IE 32位即可正常运行 问题二:无法录制百度等官网页面 原因:录制选项中 ...

  4. [LTR] RankLib.jar 包介绍

    一.介绍 RankLib.jar 是一个学习排名(Learning to rank)算法的库,目前已经实现了如下几种算法: MART RankNet RankBoost AdaRank Coordin ...

  5. 命令行选项 - Mozilla 产品与私有技术 | MDN - Google Chrome

    命令行选项 在本文章中 语法规则 使用命令行选项 示例 用户配置档 -CreateProfile profile_name -CreateProfile "profile_name prof ...

  6. Chrome_浏览器开发人员工具

    Google Chrome 浏览器开发人员工具,让网页开发变得更轻松 无论是 IE 6/7 的 Internet Explorer Developer Toolbar 或者是 IE 8 自带的 Dev ...

  7. python第六十三天-- 第十一周作业

    题目:基于RabbitMQ rpc实现的主机管理 需求: 可以对指定机器异步的执行多个命令例子:>>:run "df -h" --hosts 192.168.3.55 ...

  8. Windows下cwrsync客户端与rsync群辉存储客户端数据同步

    cwRsync简介 cwRsync是Rsync在Windows上的实现版本,Rsync通过使用特定算法的文件传输技术,可以在网络上传输只修改了的文件. cwRsync主要用于Windows上的远程文件 ...

  9. Linux永久修改系统时间

    1.date 查看系统时间 2.hwclock --show 查看硬件的时间 3.hwclock --set --date '2017-08-16 17:17:00' 设置硬件时间为17年8月16日1 ...

  10. January 13th, 2018 Week 02nd Saturday

    Anyone who has no spiritual aspirations is an idiot. 任何没有精神追求的人都是愚昧无知的人. Today I went to a bookshop ...