事务操作
1、@Transactional
springboot为我们提供了@Transactional
注解,该注解可以用于管理一个方法,一个类,一个接口,但是我们一般只使用它来管理一个方法即可,因为需要用到事务操作的一般也就是增删改这些操作
该注释在方法开始前会开启事务,在函数末尾会提交/回滚事务
2、事务传播
springboot提供了事务的一系列操作
其中,我们只需要重点关注两个属性
假设这里有两个函数,函数A和函数B,函数A里面调用了函数B,假设两个都有事务
REQUIRED
这个为Transactional的默认值,如果函数A有创建事务,那么函数B归并到函数A的事务中,如果函数A回滚了,那么函数B的操作也回滚REQUIRES_NEW
:这个与REQUIRED不同,两个事务互为独立事务,即使函数A回滚了,但是函数B实现的操作不会回滚,听起来很鸡肋是吧,不会滚我还使用事务干嘛,别急,下面就举例场景
- 函数A
@Transactional
@Override
public void deleteDeptById(Integer id) {
try {
deptMapper.deleteDeptById(id);
// 删除部门后,将部门的所有员工删除
int i = 1 / 0;//我们设计一个异常的情况
empMapper.deleteEmpsByDeptId(id);
// 无论是否删除成功 都要添加日记到数据库表中
} finally {
DeptLog deptLog = new DeptLog();
deptLog.setCreateTime(LocalDateTime.now());
deptLog.setDescription("执行了删除部门操作,此次删除的部门是" + id + "号部门");
deptLogService.insert(deptLog);
}
}
-
函数B
@Transactional(propagation = Propagation.REQUIRES_NEW) @Override public void insert(DeptLog deptLog) { deptLogMapper.insert(deptLog); }
让我们分析一下,如果使用REQUIRED
的情况,我们将函数A和函数B合并到一个事务(函数A的事务中),这时,在执行int i = 1 / 0;
时报出了一个错误,那么函数A的事务必须回滚,即使函数B在finally中已经写好了数据,但还是没有,照样回滚,日记没有写入到数据表中,如果我们使用REQUIRES_NEW
,A和B是两个独立的事务,在调用函数B时,函数A的事务被挂起,如果函数B执行成功并提交,即使抛出异常导致外层事务回滚,函数B的事务也不会回滚,意思就是说函数a回滚的范围并不包括函数b。
3、事务回滚的注意事项
// Transactional 事务管理
@Transactional(rollbackFor = Exception.class)
@Override
public void deleteDeptById(Integer id) {
try {
deptMapper.deleteDeptById(id);
// 删除部门后,将部门的所有员工删除
empMapper.deleteEmpsByDeptId(id);
// 无论是否删除成功 都要添加日记到数据库表中
} finally {
DeptLog deptLog = new DeptLog();
deptLog.setCreateTime(LocalDateTime.now());
deptLog.setDescription("执行了删除部门操作,此次删除的部门是" + id + "号部门");
deptLogService.insert(deptLog);
}
}