Spring事务的七种传播机制

一、REQUIRED(默认)

1.1、基础概念

官方解释:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

如果A、B两个方法都加了@Transactional注解,默认是REQUIRED传播行为。那么如果A方法调用B方法,它们会共用一个事务,因为默认会使用同一条连接,相当于一个事务里执行。

1.2、代码详解

例如,在插入一条用户信息以后会紧接着插入一条角色信息,最后我手动写了个除数不能为0的异常,以下是关键代码:

UserService关键代码:

@Transactional(rollbackFor = Exception.class)
    public void insertUser(){
        User user = new User();
        user.setId(UUID.randomUUID().toString());
        user.setUsername("张三");
        user.setPassword("123456");
        userMapper.insert(user);
        roleService.insertRole();
        int a = 1/0;
    }

RoleService关键代码:

    @Transactional(rollbackFor = Exception.class)
    public void insertRole(){
        Role role = new Role();
        role.setId(UUID.randomUUID().toString());
        role.setName("管理员");
        roleMapper.insert(role);
    }

运行结果如下:

虽然程序中会抛出java.lang.ArithmeticException: / by zero的异常,但事务都进行了回滚操作! 

二、SUPPORTS

2.1、基础概念

官方解释:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

如果A方法没有事务(没有加@Transactional注解),B方法配置了SUPPORTS传播行为,那么B方法也会以非事务方式执行。

如果A方法存在事务(加了@Transactional注解),B方法配置了SUPPORTS传播行为,那么B方法会挂起自己的事务,加入到A方法的事务来执行。

2.2、代码详解

整体代码逻辑依旧不变。

2.2.1、不加@Transactional注解

在insertUser方法上面不加@Transactional注解。

UserService关键代码:

    public void insertUser(){
        User user = new User();
        user.setId(UUID.randomUUID().toString());
        user.setUsername("张三");
        user.setPassword("123456");
        userMapper.insert(user);
        roleService.insertRole();
        int a = 1/0;
    }

RoleService关键代码: 

 @Transactional(rollbackFor = Exception.class,propagation = Propagation.SUPPORTS)
    public void insertRole(){
        Role role = new Role();
        role.setId(UUID.randomUUID().toString());
        role.setName("管理员");
        roleMapper.insert(role);
    }

运行结果如下:

可以很明显的看出,虽然程序中会抛出java.lang.ArithmeticException: / by zero的异常,但2条数据都成功入库了,这是因为insertUser方法没有配置事务,那么insertRole方法也会以非事务的方式进行运行。

2.2.2、加@Transactional注解

仅仅需要在insertUser方法上面加上@Transactional注解。

UserService关键代码:

@Transactional(rollbackFor = Exception.class)
    public void insertUser(){
        User user = new User();
        user.setId(UUID.randomUUID().toString());
        user.setUsername("张三");
        user.setPassword("123456");
        userMapper.insert(user);
        roleService.insertRole();
        int a = 1/0;
    }

RoleService代码不动! 

运行结果如下:

虽然程序中会抛出java.lang.ArithmeticException: / by zero的异常,但是2条数据都进行了回滚,这是因为insertRole方法配置了SUPPORTS传播行为,那么insertRole方法会挂起自己的事务,加入到inserUser方法的事务来执行。 

三、MANDATORY

3.1、基础概念

官方解释:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

如果A方法没有事务(没有加@Transactional注解),B方法配置了MANDATORY传播行为,那么B方法将会抛出异常。

如果A方法存在事务(加@Transactional注解),B方法配置了MANDATORY传播行为,那么B方法将加入到该存在的事务来执行。

3.2、代码详解

整体代码逻辑依旧不变。

3.2.1、不加@Transactional注解

在insertUser方法上面不加@Transactional注解。

UserService关键代码:

 public void insertUser(){
        User user = new User();
        user.setId(UUID.randomUUID().toString());
        user.setUsername("张三");
        user.setPassword("123456");
        userMapper.insert(user);
        roleService.insertRole();
        int a = 1/0;
    }

RoleService关键代码:

 @Transactional(rollbackFor = Exception.class,propagation = Propagation.MANDATORY)
    public void insertRole(){
        Role role = new Role();
        role.setId(UUID.randomUUID().toString());
        role.setName("管理员");
        roleMapper.insert(role);
    }

运行结果如下:

程序会抛出org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'的异常信息,数据库这边User信息入库了,但是Role信息没有,因为insertUser方法不存在事务,才导致出现这个异常并且数据成功入库。

3.2.2、加@Transactional注解

仅仅需要在insertUser方法上面加上@Transactional注解。

UserService关键代码:

  @Transactional(rollbackFor = Exception.class)
    public void insertUser(){
        User user = new User();
        user.setId(UUID.randomUUID().toString());
        user.setUsername("张三");
        user.setPassword("123456");
        userMapper.insert(user);
        roleService.insertRole();
        int a = 1/0;
    }

RoleService代码不动!

运行结果如下:

虽然程序抛出:java.lang.ArithmeticException: / by zero的异常信息,但是2条数据都进行了回滚,上面的org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'的异常信息也没有了,所以这种事务的传播机制必须需要存在一个活动的事务。

四、REQUIRES_NEW

4.1、基础概念

官方解释:创建一个新的事务,如果当前存在事务,则把当前事务挂起。

如果A、B方法都有事务,但B配置了REQUIRES_NEW,那么B会起一个新的事务,暂停A的事务。等B事务结束,才恢复A的事务。

4.2、代码详解

整体代码逻辑不变。

UserService关键代码:

 @Transactional(rollbackFor = Exception.class)
    public void insertUser(){
        User user = new User();
        user.setId(UUID.randomUUID().toString());
        user.setUsername("张三");
        user.setPassword("123456");
        userMapper.insert(user);
        roleService.insertRole();
        int a = 1/0;
    }

RoleService关键代码:

  @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public void insertRole(){
        Role role = new Role();
        role.setId(UUID.randomUUID().toString());
        role.setName("管理员");
        roleMapper.insert(role);
    }

运行结果如下:

虽然程序抛出:java.lang.ArithmeticException: / by zero的异常信息,但是Role信息插入成功了,这是因为insertUser和insertRole方法公用的不是同一个事务,也可以说是公用的不是同一个数据库链接。

五、NOT_SUPPORTED

5.1、基础概念

官方解释:以非事务方式运行,如果当前存在事务,则把当前事务挂起。

如果A方法没有事务(没有加@Transactional注解),B方法配置了NOT_SUPPORTED传播行为,那么B方法也会以非事务方式执行。

如果A方法存在事务(加了@Transactional注解),B方法配置了NOT_SUPPORTED传播行为,那么B方法会挂起自己的事务,以非事务方式加入到A方法的事务来执行。

5.2、代码详解

整体代码逻辑依旧不变。

5.2.1、不加@Transactional注解

在insertUser方法上面不加@Transactional注解。

UserService关键代码:

 public void insertUser(){
        User user = new User();
        user.setId(UUID.randomUUID().toString());
        user.setUsername("张三");
        user.setPassword("123456");
        userMapper.insert(user);
        roleService.insertRole();
        int a = 1/0;
    }

RoleService关键代码:

  @Transactional(rollbackFor = Exception.class,propagation = Propagation.NOT_SUPPORTED)
    public void insertRole(){
        Role role = new Role();
        role.setId(UUID.randomUUID().toString());
        role.setName("管理员");
        roleMapper.insert(role);
    }

运行结果如下: 

可以很明显的看出,虽然程序中会抛出java.lang.ArithmeticException: / by zero的异常,但2条数据都成功入库了,虽然insertUser方法没有配置事务,但是insertRole方法配置了NOT_SUPPORTED传播行为,那么inserRole方法也会以非事务方式执行。

5.2.2、加@Transactional注解

仅仅需要在insertUser方法上面加上@Transactional注解。

UserService关键代码:

 @Transactional(rollbackFor = Exception.class)
    public void insertUser(){
        User user = new User();
        user.setId(UUID.randomUUID().toString());
        user.setUsername("张三");
        user.setPassword("123456");
        userMapper.insert(user);
        roleService.insertRole();
        int a = 1/0;
    }

RoleService代码不动!

运行结果如下:

可以很明显的看出,虽然程序中会抛出java.lang.ArithmeticException: / by zero的异常,但是Role信息成功入库了,因为insertUser方法配置了事务,但是insertRole方法配置了NOT_SUPPORTED传播行为,那么insertRole方法会挂起自己的事务,以非事务方式加入到insertUser方法的事务来执行。

六、NEVER

6.1、基础概念

官方解释:以非事务方式运行,如果当前存在事务,则抛出异常。

如果A方法没有事务(没有加@Transactional注解),B方法配置了NEVER传播行为,那么B方法会正常以非事务方式执行。

如果A方法存在事务(加了@Transactional注解),B方法配置了NEVER传播行为,那么B方法将会抛出异常。

6.2、代码详解

整体代码逻辑依旧不变。

6.2.1、不加@Transactional注解

在insertUser方法上面不加@Transactional注解。

UserService关键代码:

public void insertUser(){
        User user = new User();
        user.setId(UUID.randomUUID().toString());
        user.setUsername("张三");
        user.setPassword("123456");
        userMapper.insert(user);
        roleService.insertRole();
        int a = 1/0;
    }

RoleService关键代码:

@Transactional(rollbackFor = Exception.class,propagation = Propagation.NEVER)
    public void insertRole(){
        Role role = new Role();
        role.setId(UUID.randomUUID().toString());
        role.setName("管理员");
        roleMapper.insert(role);
    }

运行结果如下:

可以很明显的看出,虽然程序中会抛出java.lang.ArithmeticException: / by zero的异常,但2条数据都成功入库了,这是因为insertUser方法没有配置事务,insertRole方法配置了NOT_SUPPORTED传播行为,那么insertRole方法会以非事务方式执行。

6.2.2、加@Transactional注解

仅仅需要在insertUser方法上面加上@Transactional注解。

UserService关键代码:

 @Transactional(rollbackFor = Exception.class)
    public void insertUser(){
        User user = new User();
        user.setId(UUID.randomUUID().toString());
        user.setUsername("张三");
        user.setPassword("123456");
        userMapper.insert(user);
        roleService.insertRole();
        int a = 1/0;
    }

RoleService代码不动! 

运行结果如下:

程序会抛出org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never' 的异常信息,同时2条数据都没有成功入库!因为insertUser方法配置了事务,insertRole方法配置了NEVER传播行为,那么insertRole方法抛出了异常信息。

七、NESTED

7.1、基础概念

官方解释:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于REQUIRED

如果A方法没有事务(没有加@Transactional注解),B方法配置了NESTED传播行为,那么B方法将启动一个新的嵌套事务执行。

如果A方法存在事务(加@Transactional注解),B方法配置了NESTED传播行为,那么B方法将会在嵌套事务内执行。

7.2、代码详解

整体代码逻辑依旧不变。

7.2.1、不加@Transactional注解

在insertUser方法上面不加@Transactional注解。

UserService关键代码:

  public void insertUser(){
        User user = new User();
        user.setId(UUID.randomUUID().toString());
        user.setUsername("张三");
        user.setPassword("123456");
        userMapper.insert(user);
        roleService.insertRole();
        int a = 1/0;
    }

RoleService关键代码:

  @Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)
    public void insertRole(){
        Role role = new Role();
        role.setId(UUID.randomUUID().toString());
        role.setName("管理员");
        roleMapper.insert(role);
    }

运行结果如下:

可以很明显的看出,虽然程序中会抛出java.lang.ArithmeticException: / by zero的异常,但是2条数据都成功入库了。因为insertUser方法没有配置事务,insertRole方法配置了NESTED传播行为,那么insertRole方法将启动一个新的嵌套事务执行。

7.2.2、加@Transactional注解

仅仅需要在insertUser方法上面加上@Transactional注解。

UserService关键代码:

 @Transactional(rollbackFor = Exception.class)
    public void insertUser(){
        User user = new User();
        user.setId(UUID.randomUUID().toString());
        user.setUsername("张三");
        user.setPassword("123456");
        userMapper.insert(user);
        roleService.insertRole();
        int a = 1/0;
    }

 

RoleService代码不动! 

运行结果如下:

可以很明显的看出,虽然程序中会抛出java.lang.ArithmeticException: / by zero的异常,但是2条数据都进行了回滚。 这是因为insertUser方法配置了事务,insertRole方法配置了NESTED传播行为,那么insertRole方法将会在嵌套事务内执行。

引用文章

  • 12
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值