事务回顾
概念
事务 是一组操作的集合,它是一个不可分割的工作单位,这些操作 要么同时成功,要么同时失败
操作
开启事务(一组操作开始前,开启事务): start transaction / begin
提交事务(这组操作全部成功后,提交事务):commit
回滚事务(中间任何一个操作出现异常,回滚事务): rollback
@Transactional
@Transactional
是 Spring 框架中用于声明事务的注解,它可以应用在方法或类上,定义该方法或类中的所有方法在执行时应该运行在一个事务中。通过使用 @Transactional
,可以确保数据库操作的一致性和数据的完整性,即使在出现异常时也可以回滚操作。
@Transactional
基本用法@Transactional
注解应用在方法上时,该方法的所有数据库操作都会在一个事务中执行。@Transactional
注解应用在类上时,该类的所有公共方法都会在一个事务中执行。案例
解散部门:删除部门,同时删除该部门下的员工
//删除
@Transactional //spring事务管理
@Override
public void DeleteDept(Integer id) {
deptMapper.DeleteDept(id); //根据id删除部门数据
//int i = 3/0; 异常,删除的部门数据会通过事务回滚恢复
empMapper.deleteByDeptId(id); //根据被删除的部门id 删除该部门下的员工
}
//根据部门id删除部门下的员工数据
@Delete("delete from emp where dept_id = #{deptId}")
void deleteByDeptId(Integer deptId);
注解:@Transactional
位置:业务(service)层的方法上、类上、接口上
作用:将当前方法交给spring进行事务管理,方法执行前,开启事务,成功执行完毕,提交事务,
出现异常,回滚事务
事务进阶
事务属性-回滚
默认情况下,只有出现 RuntimeException才回滚异常。rollbackFor属性用于控制出现何种异常类型,回滚事务
//删除
@Transactional(rollbackFor = Exception.class) //spring事务管理
@Override
public void DeleteDept(Integer id) {
deptMapper.DeleteDept(id); //根据id删除部门数据
//int i = 3/0; 异常,删除的部门数据会通过事务回滚恢复
empMapper.deleteByDeptId(id); //根据被删除的部门id 删除该部门下的员工
}
事务属性-传播行为
事务传播行为:指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制
案例
解散部门时,记录操作日志
需求:解散部门时,无论是成功还是失败,都要记录操作日志步骤:
1.解散部门:删除部门、删除部门下的员工
//删除
@Transactional(rollbackFor = Exception.class) //spring事务管理
@Override
public void DeleteDept(Integer id) {
try {
deptMapper.DeleteDept(id); //根据id删除部门数据
// int i = 3/0; //异常,删除的部门数据会通过事务回滚恢复
empMapper.deleteByDeptId(id); //根据被删除的部门id 删除该部门下的员工
} finally { //无论上面代码成功或失败都会执行
DeptLog deptLog = new DeptLog();
deptLog.setCreateTime(LocalDateTime.now());
deptLog.setDescription("执行了解散部门的操作,解散的部门id是:"+id);
deptLogService.insert(deptLog);
}
}
2.记录日志到数据库表中
@Service
public class DeptLogServiceImpl implements DeptLogService {
@Autowired
private DeptLogMapper deptLogMapper;
@Transactional(propagation = Propagation.REQUIRES_NEW)//调用insert方法时,会开启一个新的事务
@Override
public void insert(DeptLog deptLog) {
deptLogMapper.insert(deptLog);
}
场景
REQUIRED:大部分情况下都是用该传播行为即可。
REQUIRES_NEW:当我们不希望事务之间相互影响时,可以使用该传播行为。比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功。
在Spring事务管理中,REQUIRED
和 REQUIRES_NEW
是两种常见的事务传播行为,它们主要用于控制在方法调用过程中事务的传播方式。
REQUIRED
传播行为REQUIRED
是默认的传播行为,它表示当前方法需要在一个已有的事务中执行。如果调用方已经在一个事务中,当前方法将加入到这个事务中;如果没有,Spring 会创建一个新的事务。REQUIRED
适用于大多数情况下,因为它能确保整个业务逻辑在同一个事务中运行,这样如果在事务中的某个方法抛出了异常,整个事务会回滚,保证数据的一致性。@Transactional(propagation = Propagation.REQUIRED)
public void updateAccount() {
// 如果调用者已经有事务,加入现有事务;否则创建新事务
}
REQUIRES_NEW
传播行为REQUIRES_NEW
表示当前方法总是需要一个新的事务。无论调用方是否有事务,Spring 都会为这个方法创建一个新的事务,并且暂停调用方的事务,直到新事务完成。如果新事务回滚,不会影响调用方的事务。REQUIRES_NEW
常用于需要隔离的操作。例如,在一个大事务中,需要确保某个操作(如日志记录或事件追踪)独立于主要事务,即使主要事务回滚,也要保证这些操作能够成功完成。@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveLog() {
// 始终启动一个新事务,暂停外部事务
}
在一个复杂的业务逻辑中,多个服务或方法之间的调用可能会有不同的事务处理需求。使用 REQUIRES_NEW
时,新的事务独立于外部事务,因此即使外部事务失败回滚,REQUIRES_NEW
包含的操作仍然会成功提交。
假设在一个订单系统中,用户下订单时需要先记录操作日志。此时,saveLog
方法使用 REQUIRES_NEW
,即使订单提交失败,日志也会被成功保存。这对于追踪失败原因、审计记录等场景非常有用。
@Transactional(propagation = Propagation.REQUIRED)
public void placeOrder(Order order) {
// 记录订单日志,独立事务
saveLog(order);
// 下订单,主事务
saveOrder(order);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveLog(Order order) {
// 记录日志,确保独立于主事务,即使主事务回滚,日志也会被保存
}
在上述代码中,即使 saveOrder
发生异常并导致订单提交失败,saveLog
的日志记录也不会受到影响,这样可以确保日志记录的完整性。