tlias
事务的传递
不管怎么样,都需要记录日志
- 案例
接下来我们就通过一个案例来演示下事务传播行为propagation属性的使用。
需求:在新增员工信息时,无论是成功还是失败,都要记录操作日志。
步骤:
- 准备日志表 emp_log、实体类EmpLog、Mapper接口EmpLogMapper
- 在新增员工时记录日志
代码实现:
业务实现类:EmpServiceImpl
@Autowired
private EmpMapper empMapper;
@Autowired
private EmpExprMapper empExprMapper;
@Autowired
private EmpLogService empLogService;
@Transactional(rollbackFor = {Exception.class})
@Override
public void save(Emp emp) {
try {
//1.补全基础属性
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
//2.保存员工基本信息
empMapper.insert(emp);
int i = 1/0;
//3. 保存员工的工作经历信息 - 批量
Integer empId = emp.getId();
List<EmpExpr> exprList = emp.getExprList();
if(!CollectionUtils.isEmpty(exprList)){
exprList.forEach(empExpr -> empExpr.setEmpId(empId));
empExprMapper.insertBatch(exprList);
}
} finally {
//记录操作日志
EmpLog empLog = new EmpLog(null, LocalDateTime.now(), emp.toString());
empLogService.insertLog(empLog);
}
}
原因分析:
接下来我们就需要来分析一下具体是什么原因导致的日志没有成功的记录。
- 在执行 save 方法时开启了一个事务
- 当执行 empLogService.insertLog 操作时,insertLog设置的事务传播行是默认值REQUIRED,表示有事务就加入,没有则新建事务
- 此时:save 和 insertLog 操作使用了同一个事务,同一个事务中的多个操作,要么同时成功,要么同时失败,所以当异常发生时进行事务回滚,就会回滚 save 和 insertLog 操作
测试:
重新启动SpringBoot服务,测试新增员工操作 。我们可以看到控制台中输出的日志:

从日志中我们可以看到:
- 执行了插入员工数据的操作
- 执行了插入日志操作
- 程序发生Exception异常
- 执行事务回滚(保存员工数据、插入操作日志 因为在一个事务范围内,两个操作都会被回滚)
然后在 emp_log 表中没有记录日志数据 。
我们看到数据库的事务居然提交了,并没有进行回滚。
通过以上测试可以得出一个结论:默认情况下,只有出现RuntimeException(运行时异常)才会回滚事务。
假如我们想让所有的异常都回滚,需要来配置@Transactional注解当中的rollbackFor属性,通过rollbackFor这个属性可以指定出现何种异常类型回滚事务。
@Transactional(rollbackFor = Exception.class)
@Override
public void save(Emp emp) throws Exception {
//1.补全基础属性
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
//2.保存员工基本信息
empMapper.insert(emp);
//int i = 1/0;
if(true){
throw new Exception("出异常啦....");
}
//3. 保存员工的工作经历信息 - 批量
Integer empId = emp.getId();
List<EmpExpr> exprList = emp.getExprList();
if(!CollectionUtils.isEmpty(exprList)){
exprList.forEach(empExpr -> empExpr.setEmpId(empId));
empExprMapper.insertBatch(exprList);
}
}