七种传播方式
#指定传播方式
@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也就没有事务了。
此时因为最外层的OuterBean没有事务,所以InnerBean的testSupports方法会插入两条记录:
放开OuterBean的@Transactional批注,就能进行数据回滚了。
3. MANDATORY
mandatory本身的含义就是强制性的意思。所以说明是必须要使用事务。如果当前没有事务,则会抛出异常,如果存在当前事务,就沿用当前事务。在调用传播性为MANDATORY的方法时,强制父方法也是一个支持事务的方法。
此时就会有个异常信息:
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事务继续执行。
执行结果:inner插入了,outer回滚了。
5. NOT_SUPPORTED
总是以非事务地执行,并挂起任何存在的事务。如下图所示代码。Outer有事务,在执行Inner时事务会挂起,执行
inner的代码,Inner虽然有除0异常,但是因为是非事务方式运行,所以是会直接插入库的。抛出的异常被Outer接收
到后,Outer进行事务回滚。
执行结果:inner插入了,outer回滚了
6. NEVER
总是非事务地执行,如果存在一个活动事务,则抛出异常。和上面的NOT_SUPPORTED的区别就是会抛出异常。
如下图程序:
此时会抛出异常:
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进行区别对比。
此时数据库中不会有任何记录。
下图是子事务出现异常时,父事务是可以选择回滚或者不回滚。
此时数据库会把Outer的数据插入:
但是如果去掉OuterBean中的try-catch的话,父事务也会回滚。