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

先看两张表,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. SAP MM PIR里的Lower Limit & Upper Limit

    SAP MM PIR里的Lower Limit & Upper Limit 在PIR的价格的detail数据里,有2个字段:Lower Limit和Upper Limit.在今天之前,笔者从未 ...

  2. loadrunner 脚本开发-参数化之将内容保存为参数、参数数组及参数值获取Part 2

    脚本开发-参数化之将内容保存为参数.参数数组及参数值获取 by:授客 QQ:1033553122 ----------------接 Part 1--------------- 把内容保存到参数数组 ...

  3. Java并发编程(十)阻塞队列

    使用非阻塞队列的时候有一个很大问题就是:它不会对当前线程产生阻塞,那么在面对类似消费者-生产者的模型时,就必须额外地实现同步策略以及线程间唤醒策略,这个实现起来就非常麻烦.但是有了阻塞队列就不一样了, ...

  4. [20170927]hugepages与内核参数nr_overcommit_hugepages.txt

    [20170927]hugepages与内核参数nr_overcommit_hugepages.txt /proc/sys/vm/nr_overcommit_hugepages specifies h ...

  5. C# RSA 加密

    class Sign_verifySign { #region prepare string to sign. //example format: a=123&b=xxx&c (wit ...

  6. Dota 2 中安装包的作用

    在玩data 2 的时候有很多其他安装包的下载,那这些有啥用呢? Reborn是Dota2的重生客户端,也就是主客户端. Opengl是显卡优化的,应该是微软的一个标准,有助于提高游戏的 FPS. V ...

  7. [转]extern "C"的作用

    extern "C"的主要作用就是为了能够正确实现C++代码调用其它C语言代码. 加上extern “C”后,会指示编译器将这部分代码按C语言进行编译,而不是C++的.这是因为C+ ...

  8. 探索哪个进程使磁盘I/O升高

    如果生产环境中磁盘使用率突然升高,却不知道因为哪个应用程序导致的,这个时候我们可以使用pidstat命令来查看,比如 Linux .el7.x86_64 (ip.ec2.internal) _x86_ ...

  9. Alpha冲刺! Day7 - 砍柴

    Alpha冲刺! Day7 - 砍柴 今日已完成 晨瑶:列了各模块目前的进度情况:确定了纯多媒体流星预览页的显示方式:给工具包函数列表新增了与服务器端的交互:玩华为软件云发现刚好可以试试它的测试,于是 ...

  10. IO流(字节流,字符流,缓冲流)

    一:IO流的分类(组织架构) 根据处理数据类型的不同分为:字节流和字符流 根据数据流向不同分为:输入流和输出流   这么庞大的体系里面,常用的就那么几个,我们把它们抽取出来,如下图:   二:字符字节 ...