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

先看两张表,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. 微信 H5 支付流程以及一些坑

    原文:https://blog.niceue.com/front-end-development/wechat-h5-payment-process-as-well-as-some-pits.html ...

  2. ImageButton和ImageView设置点击透明区域不响应

    思路 ImageView和ImageButton都可以设置background和设置src,两者的区别自行度娘.由于两者的不同,获取它们的图片资源的方法也不同.倘若设置的是background,那么需 ...

  3. maven管理项目的特点

    Maven介绍 我们在开发项目的过程中,会使用一些开源框架.第三方的工具等等,这些都是以jar包的方式被项目所引用,并且有些jar包还会依赖其他的jar包,我们同样需要添加到项目中,所有这些相关的ja ...

  4. Spark程序数据结构优化

    场景: 1.scala中的对象:对象头是16个字节(包含指向对象的指针等源数据信息),如果对象中只有一个int的属性,则会占用20个字节,也就是说对象的源数据占用了大部分的空间,所以在封装数据的时候尽 ...

  5. [20170627]使用TSPITR恢复表空间.txt

    [20170627]使用TSPITR恢复表空间.txt --//RMAN提供了一种实现所谓TSPITR(Tablespace Point-In-Time Recovery)的技术,通过简单的一个语句, ...

  6. 洗礼灵魂,修炼python(54)--爬虫篇—urllib2模块

    urllib2 1.简介 urllib2模块定义的函数和类用来获取URL(主要是HTTP的),他提供一些复杂的接口用于处理: 基本认证,重定向,Cookies等.urllib2和urllib差不多,不 ...

  7. EasyUI datagrid.getSelections 没有返回正确的选择行数

    Actually i solved the problem. It was because the idField of the table i was using was incorrect. it ...

  8. January 29th, 2018 Week 05th Monday

    Losing all hope was freedom. 彻底绝望就是真正的自由. Losing all the hopes, and we are free to challenge everyth ...

  9. [BZOJ 3829][POI2014] FarmCraft

    先贴一波题面... 3829: [Poi2014]FarmCraft Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 421  Solved: 197[ ...

  10. 17秋 软件工程 团队第五次作业 Alpha Scrum2

    17秋 软件工程 团队第五次作业 Alpha Scrum2 今日完成的任务 杰麟:Java后端的学习: 世强:登录和注册接口编写: 港晨:完成数据库表的设计: 树民.陈翔:完成超级管理员后端框架. 其 ...