JAVA--多表连接(部门与员工)
部门与员工多表连接
一、多表连接的基本概念
什么是多表连接?
- 部门表:记录公司的各个部门(财务部、研发部等)
- 员工表:记录公司的所有员工
这两个表格通过部门编号关联起来--每个员工都属于某个部门,每个部门都有多个员工。
多表连接就是把这两个表格的数据关联起来,让我们能一起查看部门和员工的信息,就像把相关的信息粘在一起一样。
二、实体关系设计
一对多关系
关系说明:一个部门可以有多个员工
在代码中,会在部门对象里放一个员工列表,用来装这个部门的所有员工。
多对一关系
关系说明:多个员工属于一个部门
在代码中,会在每个员工对象里放一个部门对象,用来表示这个员工属于哪个部门。
三、多表连接的实现方式
方式一:分步查询(嵌套查询)
查询流程:
-
第一步:先查询部门信息
- 执行 SQL:
select deptno,dname,loc from dept where deptno=#{deptno} - 得到部门的基本信息
- 执行 SQL:
-
第二步:查询这个部门的所有员工
- 执行 SQL:根据员工的 deptno 字段查询
- 得到这个部门的所有员工
-
第三步:组装数据
- 把查到的员工放进部门的员工列表里
- 最终得到一个包含所有员工的部门对象
方式二:一次查询(连接查询)
查询流程:
-
一步到位:一次执行连接查询
- 执行 SQL:
select dept.deptno as dno, dname,loc,empno,ename,job,mgr,hiredate,sal,comm,emp.deptno from dept left join emp on dept.deptno=emp.deptno - 这个 SQL 会同时查询部门和员工的所有信息
- 执行 SQL:
-
自动组装:MyBatis 自动处理结果
- MyBatis 会把查询结果自动分成部门和员工两部分
- 然后把员工放进部门的员工列表里
拓展
1. INNER JOIN(内连接)
作用:只查询有员工的部门,只查询有部门的员工
通俗解释:
- 只显示两个表都有匹配数据的记录
- 相当于两个表的交集
- 没有员工的部门不会显示
- 没有部门的员工也不会显示
例子:
- 财务部有员工,会显示
- 销售部没有员工,不会显示
- 临时工没有部门,不会显示
2. RIGHT JOIN(右连接)
作用:查询所有员工,即使这个员工没有部门
通俗解释:
- 以员工表为基础(右表),去匹配部门表(左表)
- 不管员工有没有部门,都会显示员工信息
- 没有部门的员工,部门相关的字段会显示为 NULL
例子:
- 有部门的员工会显示
- 临时工没有部门,也会显示(部门信息为 NULL)
四、三种连接的区别与使用场景
连接类型对比
左连接(LEFT JOIN):
- 核心特点:以左表为基础,查询所有左表数据
- 结果特点:左表数据完整,右表可能有NULL
- 适用场景:查询所有部门,即使无员工
内连接(INNER JOIN):
- 核心特点:只查询两表匹配的数据
- 结果特点:只显示匹配数据,无NULL
- 适用场景:只查询有员工的部门
右连接(RIGHT JOIN):
- 核心特点:以右表为基础,查询所有右表数据
- 结果特点:右表数据完整,左表可能有NULL
- 适用场景:查询所有员工,即使无部门
什么时候使用什么连接
选择左连接的情况:
- 需要保证左表数据的完整性
- 想查看所有部门,包括暂时没有员工的部门
- 业务逻辑以左表为主,右表为辅助信息
选择内连接的情况:
- 只关心两表都有对应数据的记录
- 想过滤掉没有员工的部门和没有部门的员工
- 业务逻辑要求数据必须在两边都存在
选择右连接的情况:
- 需要保证右表数据的完整性
- 想查看所有员工,包括暂时没有部门的员工
- 业务逻辑以右表为主,左表为辅助信息
结合实际举例
部门管理系统:通常使用左连接,因为部门是基础,即使没有员工也需要管理
员工查询系统:可以使用右连接,确保所有员工都能被查询到
报表统计系统:根据具体需求选择,需要完整数据用左/右连接,需要准确数据用内连接
五、多表连接的实际应用
1. 部门查询实现(DeptMapper.xml)
核心实现:
- 使用LEFT JOIN:
from dept left join emp on dept.deptno=emp.deptno - SQL片段复用:使用
<include refid="empColumns"/>引入预定义的字段列表 - 字段定义:在
empColumns片段中定义了所有需要查询的字段,包括部门和员工的字段 - 结果处理:通过
resultType="en.wolfcode.domain.Dept"指定返回类型
查询流程:
- 执行连接查询:一次执行LEFT JOIN,同时获取部门和员工信息
- 字段映射:MyBatis根据字段名自动映射到实体类属性
- 数据组装:由于使用了LEFT JOIN,即使部门没有员工也会显示
五、多表连接的实际应用
1. 部门查询实现(DeptMapper.xml)
核心实现:
- 使用LEFT JOIN:
from dept left join emp on dept.deptno=emp.deptno - SQL片段复用:使用
<include refid="empColumns"/>引入预定义的字段列表 - 字段定义:在
empColumns片段中定义了所有需要查询的字段,包括部门和员工的字段 - 结果处理:通过
resultType="en.wolfcode.domain.Dept"指定返回类型
查询流程:
- 执行连接查询:一次执行LEFT JOIN,同时获取部门和员工信息
- 字段映射:MyBatis根据字段名自动映射到实体类属性
- 数据组装:由于使用了LEFT JOIN,即使部门没有员工也会显示
需理解
1. LEFT JOIN的应用
选择原因:
- 完整性:保证左表数据的完整性
- 灵活性:即使没有关联数据也能显示
- 符合业务:部门是基础数据,即使暂时没有员工也需要管理
实际效果:
- 查询所有部门,包括没有员工的部门
- 查询所有员工,包括没有部门的员工
2. 结果映射配置
你的实现:
- 部门映射:在deptMap中使用collection标签处理一对多关系
- 员工映射:在empMap中使用association标签处理多对一关系
- 自动映射:通过resultType直接指定返回类型,MyBatis自动处理映射
实际应用中的注意事项
- 字段名冲突:你的实现中已经使用了别名(如dno)来避免字段名冲突
- 空值处理:由于使用了LEFT JOIN,需要处理可能的NULL值
- 数据一致性:确保部门和员工的关联关系正确维护
六、遇到的问题及解决方法
1. 关联数据不存在
问题描述:查询结果中,关联的对象为 NULL
可能原因:
- 员工的部门编号为 NULL
- 部门不存在(被删除了)
- 映射配置错误
解决方法:
(1). 检查员工的部门编号是否正确
检查步骤:
-
数据库检查:
- 在数据库中执行 SQL:
SELECT * FROM emp WHERE deptno IS NULL OR deptno = '' - 查看结果:确认是否有员工的部门编号为 NULL 或空值
- 在数据库中执行 SQL:
-
代码检查:
- 查看员工实体类:确认 deptno 字段的类型和默认值
- 检查员工创建/更新代码:确保正确设置了部门编号
-
数据验证:
- 添加数据验证:在员工保存前检查部门编号是否有效
(2). 检查部门是否存在
检查步骤:
-
数据库检查:
- 在数据库中执行 SQL:
SELECT * FROM emp WHERE deptno NOT IN (SELECT deptno FROM dept) - 查看结果:确认是否有员工引用了不存在的部门
- 在数据库中执行 SQL:
-
数据修复:
- 方法一:为员工分配有效的部门编号
- 方法二:创建缺失的部门记录
-
代码优化:
- 添加部门存在性检查:在设置员工部门前验证部门是否存在
(3). 检查配置是否正确
检查步骤:
-
Mapper配置检查:
- 检查 SQL 语句:确认 JOIN 条件是否正确
- 检查字段映射:确保字段名与实体类属性名匹配
- 检查结果映射:确认 resultMap 配置是否正确
-
实体类检查:
- 检查属性名:确保与数据库字段名一致
- 检查关联关系:确认一对多和多对一关系配置正确
- 检查 getter/setter 方法:确保属性可以正确访问
-
测试验证:
- 编写单元测试:测试多表连接查询功能
- 断点调试:在关键处设置断点,检查数据传递和映射过程

浙公网安备 33010602011771号