Mybatis上手教程–select语句使用collection查询一对多关联关系场景
Contents
一 一对多关联场景
通常,一个部门包含多个员工信息,一个论坛包含多个帖子等等场景。那么,现在如果想要查询一个部门信息,以及该部门下包含的所有员工信息。该怎么处理呢?我们前面都是处理的一对一的关联关系。
二 一对多关联查询示例流程
1 部门表实体类添加员工字段List<Employee>
package com.knockatdatabase;
import java.util.List;
/**
* @Author:asher
* @Date:2021/10/10 11:16
* @Description:com.knockatdatabase
* @Version:1.0
*/
public class Department {
private int id;
private String deptName;
private List<Employee> employeeList;
public List<Employee> getEmployeeList() {
return employeeList;
}
public void setEmployeeList(List<Employee> employeeList) {
this.employeeList = employeeList;
}
...
}
给实体类Department 添加1个属性,数据类型是List带有Employee泛型;然后添加getter/setter。
2 DepartmentMapper.java接口文件添加新的方法
Department getDepartmentByIdWithEmployees(Integer id);
3 DepartmentMapper.xml文件添加SQL语句
<?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>
<resultMap id="oneDeptWithMoreEmps" type="com.knockatdatabase.Department">
<id column="did" property="id"></id>
<result column="dept_name" property="deptName"></result>
<collection property="employeeList" ofType="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>
</collection>
</resultMap>
<select id="getDepartmentByIdWithEmployees" resultMap="oneDeptWithMoreEmps">
select dept.id did,dept.dept_name,emp.id id,emp.last_name,emp.email,emp.gender gender
from tbl_dept dept left join tbl_employee emp
on dept.id = emp.did
where dept.id = #{id}
</select>
</mapper>
其中,新定义1个resultMap,type写Department实体类全类名,表示返回的是Department实体类。然后依次写主键字段用id,普通字段用result标签。
接下来,新起1个collection标签,property写Department实体类中的属性名,employeeList,此处的名字要严格一致。ofType,表示的是集合里的存放的对象的类型,该属性值对应哪个具体的实体类。然后,再在collection标签页中依次填Employee实体类和数据库表中的字段映射关系。
最后,写一个关联查询的SQL,注意的是,字段列表中,并没有写部门表里关于员工的字段值,因为数据库表中,也确实没有该字段。这里,只不过是我们人为的在Java bean的实体类Department上虚拟出来的一个属性字段:List<Employee>,然后紧接着就是写员工表里的字段列表。
4 Java测试代码
@Test
public void testOneDeptWithMoreEmps() {
String resource = "mybatis-config.xml";
SqlSession sqlSession = null;
try{
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
sqlSession = sqlSessionFactory.openSession();
DepartmentMapper mapper = sqlSession.getMapper(DepartmentMapper.class);
Department departmentByIdWithEmployees = mapper.getDepartmentByIdWithEmployees(1);
System.out.println(departmentByIdWithEmployees);
System.out.println(departmentByIdWithEmployees.getEmployeeList());
} catch (IOException e) {
e.printStackTrace();
}finally {
sqlSession.close();
}
}
//结果:
DEBUG [main] - Created connection 825658265.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@31368b99]
DEBUG [main] - ==> Preparing: select dept.id did,dept.dept_name,emp.id id,emp.last_name,emp.email,emp.gender gender from tbl_dept dept left join tbl_employee emp on dept.id = emp.did where dept.id = ?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 2
Department{id=1, deptName='市场部', employeeList=[Employee{id=1, lastName='黄伟', gender='男', mail='huangwei@knockatdatabase.com', department=null}, Employee{id=2, lastName='Huang', gender='?', mail='hensi163@163.com', department=null}]}
[Employee{id=1, lastName='黄伟', gender='男', mail='huangwei@knockatdatabase.com', department=null}, Employee{id=2, lastName='Huang', gender='?', mail='hensi163@163.com', department=null}]
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@31368b99]
DEBUG [main] - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@31368b99]
DEBUG [main] - Returned connection 825658265 to pool.
三 小结
association,见名知意,用于定义关联对象。通常用于一对一的对象关联场景;搭配javaType标签使用,内容为目标类的全类名;
collection,见名知意,用于定义关联集合类型。用于一对多的对象关联场景;搭配ofType标签使用,其值也为目标类的全类名;
四 补充
当然,该示例执行前,要准备好数据库里的表数据的关联关系。
mysql> select * from tbl_dept;
+----+-----------+
| id | dept_name |
+----+-----------+
| 1 | 市场部 |
| 2 | 财务部 |
+----+-----------+
2 rows in set (0.21 sec)
mysql> select * from tbl_employee;
+----+-----------+--------+------------------------------+------+
| id | last_name | gender | email | did |
+----+-----------+--------+------------------------------+------+
| 1 | 黄伟 | 男 | huangwei@knockatdatabase.com | 1 |
| 2 | Huang | ? | hensi163@163.com | 1 |
| 4 | Huang | 男 | hensi163@163.com | 2 |
| 5 | Huang | 男 | hensi163@163.com | 2 |
| 6 | Huang | 男 | hensi163@163.com | 2 |
| 7 | Huang | 男 | hensi163@163.com | 2 |
| 8 | Huang | 男 | hensi163@163.com | 2 |
| 9 | Huang | 男 | hensi163@163.com | 2 |
| 10 | Huang | 男 | hensi163@163.com | NULL |
+----+-----------+--------+------------------------------+------+
9 rows in set (0.00 sec)
mysql>