2.springboot事务-7种传播

146 阅读4分钟

七种传播方式

#指定传播方式
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)

1.REQUIRED

这种传播是默认的。含义是:如果当前方法的执行上下文中已经打开了事务,那么就使用当前这个事务。

如果当前没有事务,就创建一个新的事务。

如下面例子:inner 声明了REQUIRED,并抛出了异常,outer 事务将同样回滚,因为他们是同一个事务。

OuterBean代码:

@Service
public class OuterBean {
    @Resource
    private InnerBean innerBean;
    @Resource
    private SysParamsMapper paramsMapper;

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void testRequired(SysParams params) throws Exception {
        this.paramsMapper.insertSelective(params);
        innerBean.testRequired();
    }
}

InnerBean代码:

@Service
public class InnerBean {
    @Resource
    private SysParamsMapper paramsMapper;

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void testRequired() {
        throw new RuntimeException("抛出运行时异常");
    }
}

测试类代码:

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class TransactionalTest {
    @Resource
    private OuterBean outerBean;
    @Test
    public void testPropagation() {
        SysParams sysParams = new SysParams();
        sysParams.setAppid("REQUIRED");
        try {
            this.outerBean.testRequired(sysParams);
        } catch (Exception e) {
        }
    }
}

这里说明一点:

如果Outer Bean中调用本类的私有方法,那么其实也是会受到这个传播影响。本类的私有方法

会和public的入口方法在同一个事务中。也即是私有方法中如果抛出异常,public的入口方法同样

会进行事务回滚的。

2. SUPPORTS

支持事务,如果当前存在事务,就沿用当前事务,如果不存在,则继续采用无事务的方式运行。

这里就完全取决于OuterBean是否有事务了。如果有事务那么InnerBean也有事务;如果OuterBean没有事务,

那么InnerBean也就没有事务了。

image-20220817095545521

此时因为最外层的OuterBean没有事务,所以InnerBean的testSupports方法会插入两条记录:

image-20220817095625437

放开OuterBean的@Transactional批注,就能进行数据回滚了。

3. MANDATORY

mandatory本身的含义就是强制性的意思。所以说明是必须要使用事务。如果当前没有事务,则会抛出异常,如果存在当前事务,就沿用当前事务。在调用传播性为MANDATORY的方法时,强制父方法也是一个支持事务的方法。

image-20220817095726639

此时就会有个异常信息:

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'

放开OuterBean的@Transactional批注,就不报异常信息了。

4. REQUIRES_NEW

这个名字中的NEW就很直白的说明了它会创建一个新的事务。它会独立于外层事务,外层事务不会受到影响的。

内外层事务独立运行。

如下图例子:Outer事务会回滚,但是不影响InnerBean的事务,InnerBean是不会回滚的。当 inner 事务开启后,outer 事务会暂停,当 inner 事务结束后,Outer事务继续执行。

image-20220817100030234

执行结果:inner插入了,outer回滚了。

image-20220817100118838

5. NOT_SUPPORTED

总是以非事务地执行,并挂起任何存在的事务。如下图所示代码。Outer有事务,在执行Inner时事务会挂起,执行

inner的代码,Inner虽然有除0异常,但是因为是非事务方式运行,所以是会直接插入库的。抛出的异常被Outer接收

到后,Outer进行事务回滚。

image-20220817101506029

执行结果:inner插入了,outer回滚了

image-20220817101546720

6. NEVER

总是非事务地执行,如果存在一个活动事务,则抛出异常。和上面的NOT_SUPPORTED的区别就是会抛出异常。

如下图程序:

image-20220817101700696

此时会抛出异常:

org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'

7. NESTED

如果当前有事务,则开启子事务(嵌套事务),嵌套事务是独立提交或者回滚的;

如果当前没有事务,则新建一个事务。

如果主事务提交,会携带子事务一起提交;如果主事务回滚则子事务会一起回滚。但是子事务异常,父事务

可以选择回滚或者不回滚(方式:通过try-catch子事务的异常)。

  • 什么是子事务(嵌套事务)

和REQUIRED_NEW不同,它不会在外层事务中创建新的事务。反而是和REQUIRED一样,共用外层事务,

不同的是,嵌套事务会在业务方法执行之前设置一个savePoint回滚点,如果业务方法抛出异常,嵌套事务则

会回滚至savePoint,并且向上抛出异常。

如下图代码,当Outer出现异常的时候,Inner也会一起进行回滚。这里和REQUIRED_NEW进行区别对比。

image-20220817102355805

此时数据库中不会有任何记录。

下图是子事务出现异常时,父事务是可以选择回滚或者不回滚。

image-20220817102546410

此时数据库会把Outer的数据插入:

image-20220817102617410

但是如果去掉OuterBean中的try-catch的话,父事务也会回滚。