事务

事务是一组操作的集合,它是一个不可分割的工作单位,这些操作要么同时成功,要么同时失败。

案例

如果我们需要解散一个部门,那么部门里的员工是否还存在?答案是不存在的

service层的逻辑

 @Override
    public void delete(Integer id) {
        deptMapper.deleteById(id);

        empMapper.deleteByDeptId(id);//根据部门id删除该部门下的id
    }

大家是不是觉得这样的逻辑没有什么错误

在正常情况下是没错,那么异常情况下呢?现在我们来模拟异常

  @Override
    public void delete(Integer id) {
        deptMapper.deleteById(id);
        int i = 1/0;
        empMapper.deleteByDeptId(id);//根据部门id删除该部门下的id
    }

启动成功

Spring事务管理(rollbackFor以及propagation应用)_propagation

现在来删除 教研部 看看教研部的员工是否也会被删除

Spring事务管理(rollbackFor以及propagation应用)_spring_02

Spring事务管理(rollbackFor以及propagation应用)_propagation_03

教研部已经删除

Spring事务管理(rollbackFor以及propagation应用)_rollbackFor_04

但是教研部的员工还在

Spring事务管理(rollbackFor以及propagation应用)_spring事务管理_05

原因:

Spring事务管理(rollbackFor以及propagation应用)_spring事务管理_06

当部门删除以后,程序接着往下运行,然后出现异常,那么后面的程序就不会再执行了,这造成数据的不一致

所以我们需要将这段代码放在一个事务里,要成功一起成功,失败一起失败,成功再提交事务,失败回滚事务

Spring事务管理(rollbackFor以及propagation应用)_rollbackFor_07

Spring事务管理

注解:@Transactional

位置:业务(service)层的方法上、类上、接口上

作用:将当前方法交给spring进行事务管理,方法执行前,开启事务;成功执行完毕,提交事务;出现异常,回滚事务

所以对面上面的代码我专门只需要加入一个注解@Transactional

 		@Transactional
    @Override
    public void delete(Integer id) {
        deptMapper.deleteById(id);
        int i = 1/0;
        empMapper.deleteByDeptId(id);//根据部门id删除该部门下的id
    }

然后再yml配置中配置一下spring事务管理日志

logging:
  level:
    org.springframework.jdbc.support.JdbcTransactionManager: debug

Spring事务管理(rollbackFor以及propagation应用)_spring_08

事务进阶

事务性-回滚 rollbackFor

默认情况下,只有出现RuntimeException才回滚异常。rollbackFor属性用于控制出现何种异常类型,回滚事务

也就是说在不任何配置的情况下,只有出现RuntimeException异常才回滚,而rollbackFor可以控制出现哪种异常时再进行回滚

 @Transactional(rollbackFor = Exception.class)//所有的异常
    @Override
    public void delete(Integer id) {
        deptMapper.deleteById(id);
        int i = 1/0;
        empMapper.deleteByDeptId(id);//根据部门id删除该部门下的id
    }

事务属性-传播行为 propagation

事务传播行为:指的就是当一个事务方法被另外一个事务方法调用时,这个事务方法应该如何进行事务控制

我们现在有两个方法,a 和 b方法,都有@Transactional注解,当调用a方法时,首先会开启一个事务,

当在a方法中调用b方法时,b方法也具有事务,那么问题来了,b方法在调用的时候,是加入到a方法的事务还是自己新建一个事务呢?这就是事务的传播行为

Spring事务管理(rollbackFor以及propagation应用)_spring_09

Spring事务管理(rollbackFor以及propagation应用)_rollbackFor_10

我们要想控制事务的传播行为就需要通过propagation属性去指定传播行为

Spring事务管理(rollbackFor以及propagation应用)_propagation_11

场景

REQUIRED:大部分情况下都是用该传播行为即可

REQUIRES_NEW:当我们不希望事务之间相互影响时,可以使用该传播行为。比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功。