Java 杂谈我爱编程

MyBatis | 映射文件之 ResultMap(二)

2018-07-27  本文已影响0人  EclipseO2

在上一篇文章 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>
上一篇 下一篇

猜你喜欢

热点阅读