说明:当业务中的某个功能,需要多个操作组合执行才能完成时(如删除部门,部门下的员工也需要同步删除时),为了保证数据的一致性,需要对这些组合操作添加事务。
(根据部门ID删除员工)
@Delete("delete from tb_emp where id=#{id}")
void deleteByDeptId(Integer id);
(根据部门ID删除部门,要求删除部门的同时删除该部门下的所有员工)
@Delete("delete from tb_dept where id=#{id}")
void deleteById(Integer id);
Controller层
@RequestMapping("deleteById")
public void deleteById(Integer id) {
// 删除该部门
deptMapper.deleteById(id);
// 删除部门对应部门ID的员工
empMapper.deleteByDeptId(id);
(员工表)
(部门表)
添加事务
在SpringBoot项目中,可以使用@Transactional,给方法添加事务
@RequestMapping("deleteById")
@Transactional
public void deleteById(Integer id) {
// 删除该部门
deptMapper.deleteById(id);
// 手动添加算数异常
int i = 1 / 0;
// 删除部门对应部门ID的员工
empMapper.deleteByDeptId(id);
程序报错,事务未提交,方法未执行成功
去掉异常,删除ID为3的部门
@RequestMapping("deleteById")
@Transactional
public void deleteById(Integer id) {
// 删除该部门
deptMapper.deleteById(id);
// 删除部门对应部门ID的员工
empMapper.deleteByDeptId(id);
}
执行成功
需要注意的是,如果抛出的是Exception异常,而不是RuntimeException异常,事务会失效。
(删除ID为4的部门,部门被删除,员工并未被删除)
@RequestMapping("deleteById")
@Transactional
public void deleteById(Integer id) throws Exception {
// 删除该部门
deptMapper.deleteById(id);
// 手动设置Exception异常
if (true){
throw new Exception("发生了错误");
}
// 删除部门对应部门ID的员工
empMapper.deleteByDeptId(id);
}
因为事务捕捉的异常默认是RuntimeException,即只有发生RuntimeException事务才会回滚。可以在@Tranctionful()注解里添加rollback = Exception.class,表示发生任何异常,都回滚事务。
@RequestMapping("deleteById")
@Transactional(rollbackFor = Exception.class)
public void deleteById(Integer id) throws Exception {
// 删除该部门
deptMapper.deleteById(id);
// 手动设置Exception异常
if (true){
throw new Exception("发生了错误");
}
// 删除部门对应部门ID的员工
empMapper.deleteByDeptId(id);
}
事务传播
当事务方法,方法中调用的方法也被事务修饰,此时就存在事务传播。在@Transactional注解中,使用propagation属性设置,常用有以下两个值:
REQUIRED:默认值,表示调用自己的事务执行成功与否,同时也表示自己事务的状态;
REQUIRES_NEW:表示调用自己的事务执行成功与否,不会影响自己事务的执行。
例如在删除部门方法中设置一个删除部门日志方法,部门删除执行成功与否,该日志方法都执行
(DeptLogServiceImpl类,设置该事务的事务传播为:REQUIRES_NEW)
@Autowired
private DeptLogMapper deptLogMapper;
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertDeptLog(DeptLog deptLog){
deptLogMapper.insert(deptLog);
}
(DeptLogMapper类)
@Insert("insert into dept_log(create_time,description) values(#{createTime},#{description})")
void insert(DeptLog log);
@RequestMapping("deleteById")
@Transactional(rollbackFor = Exception.class)
public void deleteById(Integer id) throws Exception {
try {
// 删除该部门
deptMapper.deleteById(id);
if (true){
throw new Exception("发生了错误");
}
// 删除部门对应部门ID的员工
empMapper.deleteByDeptId(id);
}finally {
// 记录删除部门日志
DeptLog deptLog = new DeptLog();
deptLog.setCreateTime(LocalDateTime.now());
deptLog.setDescription("删除了ID" + id + "的部门");
deptLogService.insertDeptLog(deptLog);
}
}
(删除ID为2的部门)
(删除部门失败,不影响添加日志)
需要注意的是,事务传播属性是加在需要设置的方法上(添加日志方法),而不是调用方法上(删除部门方法)