如何实现简单的员工删除功能 内容概览:
删除员工功能 - 支持批量删除
修改员工功能 - 查询回显 + 数据更新
异常处理机制 - 全局异常处理器
员工信息统计 - 职位统计 + 性别统计
1. 批量删除员工功能 1.1 需求分析
支持单个 / 批量删除员工(通过 ID 列表操作)
需同时删除员工基本信息(emp表)和相关工作经历(emp_expr表)
业务规则 :确保主从表数据一致性,通过事务保证原子性
1.2 核心代码实现 Controller 层
1 2 3 4 5 6 7 8 9 10 @RestController @RequestMapping("/emps") public class EmpController { @DeleteMapping public Result delete (Integer[] ids) { log.info("员工删除: {}" ,Arrays.toString(ids)); return Result.success(); } }
1 2 3 4 5 6 7 8 9 10 @RestController @RequestMapping("/emps") public class EmpController { @DeleteMapping public Result delete (@RequestParam("ids") List<Integer> ids) { log.info("执行批量删除:ids={}" , ids); empService.deleteByIds(ids); return Result.success(); } }
Service 层(事务控制) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Service public class EmpServiceImpl implements EmpService { @Autowired private EmpMapper empMapper; @Autowired private EmpExprMapper empExprMapper; @Override @Transactional public void deleteByIds (List<Integer> ids) { empMapper.deleteByIds(ids); empExprMapper.deleteByEmpIds(ids); } }
Mapper 层(MyBatis 动态 SQL) xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <delete id ="deleteByIds" > DELETE FROM emp WHERE id IN <foreach collection ="ids" item ="id" open ="(" close =")" separator ="," > #{id} </foreach > </delete > <delete id ="deleteByEmpIds" > DELETE FROM emp_expr WHERE emp_id IN <foreach collection ="empIds" item ="empId" open ="(" close =")" separator ="," > #{empId} </foreach > </delete >
2. 修改员工功能 2.1 查询回显实现(复杂结果集映射) 数据库表关联查询 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <resultMap id ="empWithExprResultMap" type ="Emp" > <id column ="emp_id" property ="id" /> <result column ="username" property ="username" /> <result column ="name" property ="name" /> <collection property ="exprList" ofType ="EmpExpr" > <id column ="expr_id" property ="id" /> <result column ="company" property ="company" /> <result column ="start_time" property ="startTime" /> <result column ="end_time" property ="endTime" /> </collection > </resultMap > <select id ="getEmpById" resultMap ="empWithExprResultMap" > SELECT e.id AS emp_id, e.username, e.name, ee.id AS expr_id, ee.company, ee.start_time, ee.end_time FROM emp e LEFT JOIN emp_expr ee ON e.id = ee.emp_id WHERE e.id = #{id} </select >
2.2 更新员工实现(动态 SQL + 事务)
主表动态更新 xml
1 2 3 4 5 6 7 8 9 10 <update id ="updateEmp" > UPDATE emp <set > <if test ="username != null" > username = #{username},</if > <if test ="name != null" > name = #{name},</if > <if test ="gender != null" > gender = #{gender},</if > update_time = NOW() </set > WHERE id = #{id} </update >
Service 层事务逻辑 java
1 2 3 4 5 6 7 8 9 10 11 12 13 @Override @Transactional public void updateEmp (Emp emp) { empMapper.updateEmp(emp); empExprMapper.deleteByEmpId(emp.getId()); if (!CollectionUtils.isEmpty(emp.getExprList())) { emp.getExprList().forEach(expr -> expr.setEmpId(emp.getId())); empExprMapper.insertBatch(emp.getExprList()); } }
3. 全局异常处理机制 3.1 统一异常处理器 java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public Result<String> handleGlobalException (Exception ex) { log.error("全局异常:{}" , ex.getMessage(), ex); return Result.error("服务器内部错误,请联系管理员" ); } @ExceptionHandler(SQLIntegrityConstraintViolationException.class) public Result<String> handleDuplicateException (SQLIntegrityConstraintViolationException ex) { if (ex.getMessage().contains("Duplicate entry" )) { return Result.error("数据已存在,请勿重复提交" ); } return Result.error("数据库操作失败" ); } @ExceptionHandler(BusinessException.class) public Result<String> handleBusinessException (BusinessException ex) { return Result.error(ex.getMessage()); } }
4. 员工信息统计功能 4.1 职位统计(SQL 分组 + 数据转换) Mapper 层统计 SQL xml
1 2 3 4 5 6 7 8 9 10 11 12 <select id ="countJobStatistics" resultType ="map" > SELECT CASE job WHEN 1 THEN '班主任' WHEN 2 THEN '讲师' ELSE '其他职位' END AS position, COUNT(*) AS count FROM emp GROUP BY job ORDER BY count DESC </select >
Service 层数据封装 java
1 2 3 4 5 6 7 8 9 10 public Map<String, Object> getJobStatistics () { List<Map<String, Object>> list = empMapper.countJobStatistics(); List<String> positions = list.stream().map(m -> (String) m.get("position" )).collect(Collectors.toList()); List<Integer> counts = list.stream().map(m -> (Integer) m.get("count" )).collect(Collectors.toList()); return new HashMap <>() {{ put("labels" , positions); put("data" , counts); }}; }
4.2 性别统计(使用 IF 函数分组) Mapper 层统计 SQL xml
1 2 3 4 5 6 7 <select id ="countGenderStatistics" resultType ="map" > SELECT IF(gender = 1, '男', '女') AS gender, COUNT(*) AS count FROM emp GROUP BY gender </select >
返回结果示例 json
1 2 3 4 { "gender" : [ "男" , "女" ] , "count" : [ 15 , 8 ] }
🎯 关键知识点总结 1. 批量操作处理
MyBatis 技巧 :使用<foreach>标签实现 IN 条件,collection属性支持List/Array
参数传递 :Controller 层需用@RequestParam("ids")接收数组参数
2. 复杂结果映射
一对多关联 :通过<collection>标签映射主从表关系,需使用别名避免字段冲突
性能优化 :使用LEFT JOIN保留主表数据,即使从表无记录也能正常回显
3. 事务管理要点
注解范围 :@Transactional应添加在 Service 层方法上,而非 Mapper 层
操作顺序 :更新关联数据时建议先删除旧数据再插入新数据,避免唯一键冲突
4. 异常处理最佳实践
分层处理 :区分业务异常(BusinessException)和技术异常(数据库异常)
友好提示 :对唯一性约束异常等特定场景返回明确错误信息,避免暴露数据库细节
5. 统计查询技巧
数据转换 :使用CASE WHEN或IF函数将数据库枚举值转换为前端展示文本
结果适配 :将统计结果封装为{labels, data}格式,直接对接 ECharts 等图表组件
🚦 联调测试要点 1. 批量删除测试
单条测试 :传入单个 ID,验证emp和emp_expr表对应记录是否删除
批量测试 :传入多个 ID(如 [1,3,5]),检查事务是否保证全部成功或回滚
边界测试 :传入空列表、重复 ID,验证接口是否抛出合理异常
2. 修改功能测试
基本信息更新 :修改姓名、手机号等字段,验证数据库是否正确更新
工作经历变更 :新增 / 删除工作经历条目,确保旧数据清除且新数据正确插入
唯一约束测试 :尝试修改手机号为已存在的值,验证是否触发唯一性异常
3. 统计功能验证
数据分组 :检查不同职位 / 性别的统计结果是否与实际数据一致
特殊值处理 :测试gender为NULL的记录是否被正确归类(可自定义默认值)
格式校验 :确认返回数据结构符合前端图表组件的要求(如数组顺序、字段名)
📚 扩展建议
权限控制 :为删除 / 修改功能添加角色校验(如仅管理员可操作)
日志审计 :记录员工操作日志(操作人、时间、数据前后对比)
性能优化 :对高频查询添加缓存(如使用 Redis 存储统计结果)
分页支持 :在统计接口中添加分页参数,避免大数据量下性能问题
通过本指南,可完整实现企业级员工管理系统的核心功能,覆盖 CRUD、事务控制、异常处理及数据统计等关键场景,满足中大型应用的业务需求。