事务的传播

事务传播特性详解


假设我有一个Service叫做A,另一个Service 叫做B。

(1) A中事务a1调用A中事务a2
(2) A中事务a1调用B中事务b1

  • (1)(2)有区别吗?
  • 几种事务传播机制的区别。

配置事务是只配置当前方法与调用它的方法之间的传播关系,而不是当前方法和它里面的方法之间的关系。即有甲乙丙三个方法。甲调用乙,乙再调用丙,在乙方法上面配置的事务传播,只是针对甲乙之间的传播关系,而不是乙丙之间的传播关系。乙丙之间的传播关系,应该在丙上面配置。

一、 (1)(2)有区别吗

有区别。请看事务传播的requires_new。

二、事务的传播

Propagation.REQUIRED

如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。这里传播方式很好理解。不过,我还是写个例子测试一波。

@Service
@Service
public class AImpl implements A {
    @Autowired
    private UserMapper userDao;
    @Transactional
    @Override
    public void a1() {
        userDao.insert(1,"user1");
        a2();
    }
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void a2() {
        userDao.insert(2,"user2");
        throw new RuntimeException("抛个可爱的异常!");
    }
}

测试代码:

@SpringBootTest
@RunWith(SpringRunner.class)
public class Test {
    @Autowired
    private A a;
    @Autowired
    private B b;

    @org.junit.Test
    public void test(){
        /*A中事务a1调用a2*/
        a.a1();
    }
}

我在a1中调用了a2,a1存在事务。而我定义a2的事务传播方式为Propagation.REQUIRED,当a2发现当前存在事务时,不会在创建一个事务。所以,当a2中发生异常后,a1、a2都会回滚的。运行结果如图1所示
在这里插入图片描述

图1 事务传播required

Propagation.REQUIRES_NEW

总是开启一个事务。父事务不会影响子事务,子事务会影响父事务(子事务通过抛出异常影响)。除非父事务捕获了自事务抛出的异常,否则父事务也会回滚。

@Service
public class AImpl implements A {
    @Autowired
    private UserMapper userMapper;
    @Transactional
    @Override
    public void a1() {
        userMapper.insert(1,"user1");
        try {
            a2();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void a2() {
        userMapper.insert(2,"user2");
        throw new RuntimeException("抛个可爱的异常!");
    }
}

运行结果如图2所示。
在这里插入图片描述

图2 requires_new在同一个service中的调用

按道理只会插入user1,为什么插入了user2。难道在同一个service中使用requires_new方式,a1调用a2不行。于是我将a1调用a2改为调用b1。代码如下

@Service
public class AImpl implements A {
    @Autowired
    private B b;
    @Autowired
    private UserMapper userMapper;
    @Transactional
    @Override
    public void a1() {
        userMapper.insert(1,"user1");
        try {
            b.b1();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void a2() {
        userMapper.insert(2,"user2");
        throw new RuntimeException("抛个可爱的异常!");
    }
}

@Service
public class BImpl implements B {
    @Autowired
    private UserMapper userMapper;
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void b1() {
        userMapper.insert(2,"user2");
        throw new RuntimeException("抛个可爱的异常!");
    }
    @Transactional
    @Override
    public void b2() {
       //
    }
}

此次,运行结果正常,的确只插入了user1。运行结果如图3所示。
在这里插入图片描述

图3 requires_new 在不同service中的测试

所以,在同一个service中使用requires_new,内层方法并不会开启新的事务,就像required一样。

如果在同一个service类中定义的两个方法, 内层REQUIRES_NEW并不会开启新的事务,save和update中回滚都会导致整个事务的回滚
如果在不同的service中定义的两个方法, 内层REQUIRES_NEW会开启新的事务,并且二者独立,事务回滚互不影响

总结

对于requires_new,在同一个service里面两个方法的调用,内层方法并不会开启新的事务,就行required一样。而不同service的两个方法的调用,内层方法总是会开启一个新的事务。

参考文献

Spring编程:Spring事务的传播特性和隔离级别
Creating and Configuring an Oracle Database
Oracle中如何创建数据库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值