一对多,多对一的关系
Dept与Emp多表连接
一、项目概述
本项目实现了部门(Dept)和员工(Emp)之间的多表连接查询,通过MyBatis框架实现一对多和多对一的关系映射。
1 关系说明
- 一对多:一个部门有多个员工(Dept → Emp)
- 多对一:多个员工属于一个部门(Emp → Dept)
二、实体类设计
2.1 Dept.java(部门实体类)
package cn.wolfcode.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
private Long deptno; // 部门编号
private String dname; // 部门名称
private String loc; // 部门位置
private List<Emp> empList; // 一对多:一个部门有多个员工
}
2.2 Emp.java(员工实体类)
package cn.wolfcode.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
private Long empno; // 员工编号
private String ename; // 员工姓名
private String job; // 员工职位
private Long mgr; // 上级编号
private LocalDate hiredate; // 入职日期
private Double sal; // 工资
private Double comm; // 奖金
private Long deptno; // 部门编号
private Dept dept; // 多对一:一个员工属于一个部门
}
三、MyBatis配置详解
3 DeptMapper.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="cn.wolfcode.mapper.DeptMapper">
<!-- 步骤1:定义结果映射 -->
<resultMap id="deptMap" type="Dept">
<!-- 部门主键映射 -->
<id column="dept_deptno" property="deptno" />
<!-- 部门基本属性映射 -->
<result column="dname" property="dname"/>
<result column="loc" property="loc"/>
<!-- 步骤2:一对多关联映射 -->
<collection property="empList" ofType="cn.wolfcode.domain.Emp">
<!-- 员工主键映射 -->
<id column="empno" property="empno"/>
<!-- 员工基本属性映射 -->
<result column="ename" property="ename"/>
<result column="job" property="job"/>
<result column="mgr" property="mgr"/>
<result column="hiredate" property="hiredate"/>
<result column="sal" property="sal"/>
<result column="comm" property="comm"/>
<result column="emp_deptno" property="deptno"/>
</collection>
</resultMap>
<!-- 步骤3:定义SQL片段(可复用) -->
<sql id="deptColumns">
dept.deptno as dept_deptno, dname, loc,
empno, ename, job, mgr, hiredate, sal, comm,
emp.deptno as emp_deptno
</sql>
<!-- 步骤4:编写多表连接查询 -->
<select id="findAll" resultMap="deptMap">
select <include refid="deptColumns"/>
from dept left join emp on dept.deptno=emp.deptno
</select>
</mapper>
SQL查询详解
select
dept.deptno as dept_deptno, -- 部门编号(带别名避免冲突)
dname, -- 部门名称
loc, -- 部门位置
empno, -- 员工编号
ename, -- 员工姓名
job, -- 员工职位
mgr, -- 上级编号
hiredate, -- 入职日期
sal, -- 工资
comm, -- 奖金
emp.deptno as emp_deptno -- 员工的部门编号(带别名)
from dept
left join emp on dept.deptno=emp.deptno -- 左连接,确保没有员工的部门也能查到
关键点说明:
left join:左连接,确保即使部门没有员工也能查询到该部门as dept_deptno:为dept表的deptno列添加别名,避免与emp表的deptno冲突as emp_deptno:为emp表的deptno列添加别名,避免与dept表的deptno冲突
四、执行流程详解
步骤1:测试方法调用
@Test
public void test2() throws IOException {
List<Dept> deptList = deptMapper.findAll();
deptList.stream().forEach(System.out::println);
}
步骤2:Mapper实现类执行
public class DeptMapperImpl implements DeptMapper {
@Override
public List<Dept> findAll() {
// 获取SqlSession
SqlSession sqlSession = MyBatisTool.getSqlSession();
try {
// 调用映射接口方法
List<Dept> deptList = sqlSession.getMapper(DeptMapper.class).findAll();
return deptList;
} finally {
// 关闭SqlSession
MyBatisTool.close(sqlSession);
}
}
}
步骤3:MyBatis工具类创建SqlSession
public class MyBatisTool {
public static SqlSession getSqlSession() {
try (InputStream is = Resources.getResourceAsStream("mybatis-config.xml")) {
// 创建SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
// 创建SqlSession
return factory.openSession();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
步骤4:MyBatis执行SQL查询
1. 加载mybatis-config.xml配置文件
2. 加载DeptMapper.xml映射文件
3. 根据方法名findAll找到对应的SQL语句
4. 执行SQL:select ... from dept left join emp on dept.deptno=emp.deptno
5. 获取数据库查询结果集
步骤5:MyBatis结果映射
对于查询结果中的每一行数据:
1. 读取dept_deptno列,创建或获取对应的Dept对象
2. 读取dname和loc列,设置到Dept对象
3. 读取empno列,创建Emp对象
4. 读取员工相关列,设置到Emp对象
5. 将Emp对象添加到Dept对象的empList中
6. 重复直到处理完所有行
步骤6:返回结果
返回List<Dept>,每个Dept对象包含:
- deptno: 部门编号
- dname: 部门名称
- loc: 部门位置
- empList: 该部门的所有员工列表
浙公网安备 33010602011771号