Spring事务传播属性之REQUIRES_NEW用法

@Transactional中可以设置以下7种事务传播行为

  1. REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
  2. SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
  3. MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
  4. REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
  5. NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  6. NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  7. NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。

通常我们只会用到@Transactional(propagation = Propagation.REQUIRED)在特殊需求的时候需要在一个方法内部提前提交一部分事务或者是让内部的一段代码处于单独的一个事务管理的时候需要用到REQUIRES_NEW

例如下面示例中的methodA需要单独开启事务,不受调用方法事务的回滚而回滚:

@transaction    
public void testMethod(){
     dosomethingBefore...
     methodA();
     dosomgthingAfter...
} 

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodA(){
     updateSomething();
} 

假设我们在Controller直接调用testMethod() Spring会帮我们开启一个事务
运行到methodA()这行的时候会挂起当前事务,然后重新创建一个事务,在methodA()中没有发生异常的情况下,运行完methodA方法直接提交methodA的事务;后续再执行dosomgthingAfter。

总共会有4种情况:

  • dosomethingBefore发生异常,这时methodA()未运行也就没有事务,直接回滚testMethod()的事务。
  • updateSomething发生异常,回滚methodA()的事务,此时如果testMethod()对这个异常进行了try catch捕获,testMethod的事务照常提交。
  • updateSomething发生异常,回滚methodA()的事务,此时如果testMethod()没有对这个异常进行try catch捕获,那么methodA和testMethod的事务都会回滚。
  • 前面全部正常 dosomgthingAfter 发生异常,这时methodA()事务已经提交 testMethod()所做的修改会回滚。