MyBatis

Mybatis上手教程–select语句的resultMap配合association使用案例

一 association标签的使用场景

  • 对于多表关联查询时,查询员工时连带其所在部门信息一起查询的场景。除了类似前面通过resultMap的级联属性配置的场景之外,还可以使用association标签来实现。
  • 另外,对于分步查询的场景也可以使用association标签。

二association标签实现多表联合查询

在SQL mapper文件里重新写一个resultMap标签:

    <resultMap id="myEmpDeptAssociation" type="com.knockatdatabase.Employee">
       <id column="id" property="id"></id>
       <result column="last_name" property="lastName"></result>
       <result column="gender" property="gender"></result>
       <result column="email" property="mail"></result>
       <association property="department" javaType="com.knockatdatabase.Department">
           <id column="did" property="id"></id>
           <result column="dept_name" property="deptName"></result>
      </association>
  </resultMap>

关于association标签的解释:首先,我们可以从字面意思上可以理解association本身就表示关联、联盟的意思。

  • property=“department”表示的是,要对员工信息表对应的实体类Employee里的成员变量department进行关联,即员工信息表对应的实体类Employee里的成员属性名叫什么,这里就写什么;
  • javaType=”com.knockatdatabase.Department”表示的是,Employee实体类的department属性,指向我这个实体类;

这样一来,就相当于是Employee实体类里的属性department指定了对应的数据类型。跟前面我们使用级联设置属性达到了相同的目的和作用。

然后,在SQL mapper文件里写的SQL,就是这样的:

    <select id="getEmployeeAndDepartmentById" resultMap="myEmpDeptAssociation">
      select emp.id,emp.gender,emp.email as email,emp.last_name,emp.did did,dept.dept_name
      from tbl_employee emp,tbl_dept dept
      where emp.did=dept.id and emp.id=#{id}
  </select>

即,resultMap指向了这个新配置的带有association标签的myEmpDeptAssociation。然后,Java测试类里执行的结果依然是正确的。

三 association实现分步查询的场景

我们想要实现查询员工信息的同时,顺带查询部门信息,除了上述的多表关联查询,也可以使用分步查询。即先通过查询员工信息表,传入员工id作为参数,这样可以获取员工所在的部门id,然后用这个部门id当作参数,去查询部门信息表,这样就获得了部门信息,最后把员工信息和部门信息拼接在一起。就相当于通过分步的方式,获取员工信息的同时也获取了部门信息。完整流程如下:

1 先创建和实体类Department对应的接口,DepartmentMapper.java
package com.knockatdatabase.dao;

import com.knockatdatabase.Department;

/**
* @Author:asher
* @Date:2021/10/11 17:15
* @Description:com.knockatdatabase.dao
* @Version:1.0
*/
public interface DepartmentMapper {

   Department getDepartmentById(Integer id);
}
2 新建并配置对应的SQL mapper文件,DepartmentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
       <!DOCTYPE mapper
               PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
               "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.knockatdatabase.dao.DepartmentMapper">
       <select id="getDepartmentById" resultType="com.knockatdatabase.Department">
               select id,dept_name as deptName from tbl_dept where id=#{id}
      </select>
</mapper>
3 Mybatis配置文件里添加关于DepartmentMapper.xml文件的配置
<mappers>
   <mapper resource="Employee.xml"/>
   <mapper resource="EmployeeMapper.xml"/>
   <mapper resource="DepartmentMapper.xml"></mapper>
</mappers>

前面3个步骤,相当于是做的准备工作。即,通过部门id获取部门信息的SQL,给后续的分步查询员工信息做准备。

4 EmployeeMapper.java定义新的方法
    Employee getEmployeeAndDepartmentByIdStep(Integer id);

注意,这里是1个新的方法。

5 SQL mapper文件EmployeeMapper.xml添加resultMap和association以及SQL
<!--    分步查询的思路
     1 先根据员工id查询员工信息,并获取部门id;
     2 根据查询的部门id当作参数,去查询并获取部门信息;
     3 把查询到的部门信息,设置到查询出来的员工信息里去。
-->
   <resultMap id="getEmpAndDeptByStep" type="com.knockatdatabase.Employee">
       <id column="id" property="id"></id>
       <result column="last_name" property="lastName"></result>
       <result column="email" property="mail"></result>
       <result column="gender" property="gender"></result>
<!--       association标签来定义关联对象department的属性-->
<!--       表示的是关联的对象department通过select指定的包.方法来获取
           然后,column=“did“,表示的是,我前面的查询里获取到的结果,作为参数,传递给这个方法-->
       <association property="department" select="com.knockatdatabase.dao.DepartmentMapper.getDepartmentById" column="did">
      </association>
  </resultMap>
   <select id="getEmployeeAndDepartmentByIdStep" resultMap="getEmpAndDeptByStep">
       select * from tbl_employee where id=#{id}
  </select>

注意:这里的核心思路:

  • 先新建1个resultMap,resultMap id=”getEmpAndDeptByStep” type=”com.knockatdatabase.Employee”,用于处理查询员工表及其关联department表的信息的;此处的id标签和result标签跟以前的方式一样配置;
  • 通过<association property=”department” select=”com.knockatdatabase.dao.DepartmentMapper.getDepartmentById” column=”did”>配置,就比较有意思了,指定员工信息表对应的Javabean的属性字段department,是通过select属性指定的对应的接口.方法来获取的,其中,column字段表示的是用哪个查询出来的字段当作参数,传递给该方法,并从该方法中去获取对应的部门信息;
  • 最后把获取到的部门信息拼接到员工信息上去,这样就形成了一个完整的员工信息;
6 Java测试代码
@Test
public void testGetEmployeeAndDepartmentByIdStep() {
   String resource = "mybatis-config.xml";
   SqlSession sqlSession = null;
   try{
       InputStream inputStream = Resources.getResourceAsStream(resource);
       SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
       sqlSession = sqlSessionFactory.openSession();
       EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
       Employee employeeAndDepartmentById = mapper.getEmployeeAndDepartmentByIdStep(1);
       System.out.println("employee info: " + employeeAndDepartmentById);
       Department department = employeeAndDepartmentById.getDepartment();
       System.out.println("department info:" + department);
  } catch (IOException e) {
       e.printStackTrace();
  } finally {
       sqlSession.close();
  }
}
//结果
employee info: Employee{id=1, lastName='黄伟', gender='男', mail='huangwei@knockatdatabase.com', department=Department{id=1, deptName='市场部'}}
department info:Department{id=1, deptName='市场部'}

四小结

利用resultMap结合association标签一起使用,可以构成比较复杂一点儿的查询。当然,这种场景在实际工作场景中是否真的实用,我暂时还不是特别清楚。至少,我觉得这个分步查询,只是一个功能性的东西而已,可能并不实用。远不及一条关联查询来的更方便直接高效又简洁。