MyBatis | 映射文件之 ResultMap(二)

在上一篇文章 MyBatis | 映射文件之 ResultMap(一)中,简述了如何使用 ResultMap,以及如何使用 ResultMap 进行一对一的关联查询。这一篇我将说明如何使用 ResultMap 进行一对多的关联查询

一、说明与准备

为了便于学习,我仍然会贴出表结构和 POJO 的设计,下面是实验前的环境搭建

employee 的 dept_id 关联 department 表的 id 字段,即 id 是 dept_id 的外键。这和上一篇的创建是一致的

employee表

department 表

Employee.java

public class Employee {

    private Integer id;
    private String lastName;
    private String email;
    private Integer gender;
    private Department department;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }
        ...
}

Department:这里我设置了一个类型为 Employee 的 List 集合,对应数据库表中一个部门可以有多个员工

public class Department {

    private Integer id;
    private String departName;
    private List<Employee> employees;
    
    public void setEmployees(List<Employee> employees) {
        this.employees = employees;
    }
    
    public List<Employee> getEmployees() {
        return employees;
    }
        ...
}


二、使用 ResultMap 进行一对多关联查询

需求是,使用 sql 语句,查询出每个部门的信息,以及每个部门所关联的员工信息。由于一个部门对应多个员工,即一对多,这里我们使用 LEFT JOIN 对字段进行连接

1. 使用 collection 进行两张表的关联查询

类似于上一篇中介绍的一对一的关联查询,不过上一篇中关联的是一个对象,不这里关联的是一个集合。至于 collection,我会结合代码进行讲解

①. 首先创建一个集合类
DepartmentMapper.java

public interface DepartmentMapper {
    public Department getDepartmentAndList(Integer id);
}



②. 配置 sql 映射文件
下面是 DepartmentMapper.xml 的配置信息,sql 语句如下,当然是使用外键关联

<select id="getDepartmentAndList" resultMap="dept">
    SELECT d.id did, d.depart_name, e.id eid, e.last_name, email, gender 
    FROM department d 
    LEFT JOIN employee e 
    ON d.id = e.dept_id 
    WHERE d.id = #{id}
</select>

接下来写 resultMap 的配置:外层的 id 和 result 标签,是配置 Department 类(表)的,collection 标签里面的 id 和 result 标签,都是用来配置与 Department 类关联的 Employee 类(表)的。(PS:由于我在 mybatis.xml 主配置文件中配置了使用别名,因此类型都是以别名显示。否则需要全类名。)

collection 标签里定义的集合对象,这里定义的是 Employee 类型的集合
property:指定 Department 对象里面包含的 Employee 集合对象,即 List<Employee> employees
ofType:指定集合的类型

<!-- 使用嵌套结果集的方式, 使用 collection 标签定义关联的集合类型的封装规则 -->
<resultMap type="Department" id="dept">
    <!-- Deparment 类的配置 -->
    <id column="id" property="id"/>
    <result column="depart_name" property="departName"/>
    
    <!-- Employee 类的配置 -->
    <collection property="employees" ofType="Employee">
        <id column="id1" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
    </collection>
</resultMap>


③. 结果
测试语句我不写了,我们传入 Employee 的 id 为 1,直接贴出结果

Department [id=1, departName=开发部]
[Employee [id=1, lastName=Tom, email=tom@126.com, gender=0], 
Employee [id=2, lastName=Peter, email=peter@qq.com, gender=1], 
Employee [id=7, lastName=ljk, email=lkj@123.com, gender=1], 
Employee [id=15, lastName=lkj, email=lkj@123.com, gender=2]]

同时贴出使用同样 sql 语句和同样 id 的数据库查询的结果

+-----+-------------+------+-----------+--------------+--------+
| did | depart_name | eid  | last_name | email        | gender |
+-----+-------------+------+-----------+--------------+--------+
|   1 | 开发部      |    1 | Tom       | tom@126.com  |      0 |
|   1 | 开发部      |    2 | Peter     | peter@qq.com |      1 |
|   1 | 开发部      |    7 | ljk       | lkj@123.com  |      1 |
|   1 | 开发部      |   15 | lkj       | lkj@123.com  |      2 |
+-----+-------------+------+-----------+--------------+--------+

可以看到,使用 resultMap 查询出来的结果和数据库查询的结果一致,而且 Employee 确实是以 List 集合的形式出现的。

⭐⭐⭐遇到的坑:
在查询的过程中,遇到了一个毕竟大的坑🕳,当时找了快几个小时╯︿╰,这里说明一下,防患于未来。。
先斩后奏把。column 里面的值一定要与查询出来的列名相一致, 如果使用列的别名, 则 column 的值就是列的别名

拿上面的 sql 为例,我们看一下使用别名查询出来的列名

| did | depart_name | eid | last_name | email | gender |

以 id 这个字段为例子,我们注意一下 resultMap 里面配置的两个 id 标签对应的 column 对应的值,可以看到对应的是 sql 语句(SELECT d.id did, e.id eid ... FROM department d...)中设置的别名 dideid

<resultMap type="Department" id="dept">
    <id column="did" property="id"/>
    ...
    <collection property="employees" ofType="Employee">
        <id column="eid" property="id"/>
        ....
    </collection>
</resultMap>

如果你没有设置别名(SELECT d.id, e.id ... FROM department d...),同时你在两个 id 标签的 column 直接填 id,那么就会出问题。。血的教训😭

| id | depart_name | id1 | last_name | email | gender |

不用别名查询出来的表的列名结构是这样的,如果真要用,可以这样配置。这样也是可以查询出结果的,不过并不推荐。还是使用别名把!!!

<resultMap type="Department" id="dept">
    <id column="d1" property="id"/>
    ...
    <collection property="employees" ofType="Employee">
        <id column="id1" property="id"/>
        ....
    </collection>
</resultMap>


2. 使用 collection 进行两张表的分布查询

使用 association 进行分布查询,实则分三步:

  1. 先根据部门 id 查询出部门所有信息:select * from department where id = ?
  2. 根据部门查询出来的 id(外键),用于查询部门对应的多个员工信息:select * from employee where dept_id = ?
  3. 将员工信息关联到部门信息

先创建一个接口类

public interface DepartmentMapper {
    public Department getDepartmentStep(Integer id);
}

查询部门 Department 类的配置

<select id="getDepartmentStep" resultMap="empStep">
    select id, depart_name from department where id = #{id}
</select>

查询员工 Employee 类的配置

<select id="getEmployeeByDeptId" resultType="Employee">
    select id, last_name, gender, email, dept_id from employee where dept_id = #{deptId}
</select>

配置 resultMap,注意 collection 中的 column 属性对应数据库中的列名

<resultMap type="Department" id="empStep">
    <!-- Department 类的配置 -->
    <id column="id" property="id"/>
    <result column="depart_name" property="departName"/>
    
    <!-- 
        使用 collection 定义分段的集合类型的属性 
     -->
    <collection property="employees" 
        select="edu.just.mybatis.dao.EmployeeMapper.getEmployeeByDeptId"
        column="id">
    </collection>
</resultMap>

结果:

[Employee [id=1, lastName=Tom, email=tom@126.com, gender=0, department=null], 
Employee [id=2, lastName=Peter, email=peter@qq.com, gender=1, department=null], 
Employee [id=7, lastName=ljk, email=lkj@123.com, gender=1, department=null], 
Employee [id=15, lastName=lkj, email=lkj@123.com, gender=2, department=null]]


3. 使用延迟加载

collection 标签中的延迟加载比较简单,直接在 collection 里面设置 fetchType 属性值为 lazy 即可
fetchType="lazy" 表示使用延迟加载
fetchType="eager" 表示立即加载

<resultMap type="Department" id="empStep">
    ...
    <collection property="employees" 
        ...
        fetchType="lazy">
    </collection>
</resultMap>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343