如何只回滚内部方法而不影响外部方法?

how to only rollback inner method and do not influence outer method?

@Transactional
public void foo(){
    doSomthing();
    try{
        bar();
    }catch(BizException e){
        logger.warn("call bar failed",e);
        // do some work here
    }
    doSomethingElse();

}
@Transactional
public void bar(){
    // ...
    if(meetSomeCondition){
        throw new BizException(...);
    }
    // ...
}

如果 bar throw BizException ,即使在 foo 中明确捕获异常,最后它仍然回滚并抛出异常

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:720)

有一些解决方案,但我发现它不适合我的情况

例如

@Transactional(noRollbackFor=BizException.class)

因为在 foo 中也会抛出 BizException 并且在这种情况下应该回滚。

@Transactional(propagation=Propagation.REQUIRES_NEW)
public void bar()

如果明确指定传播是REQUIRES_NEW,当调用bar()时它将创建一个新会话,并且只回滚这个会话。但它存在其他情况,如果 bar 失败,所有进程将回滚。

所以现在我的临时解决方案是

public void anotherBarWithoutTransaction(){
    // ...
    if(meetSomeCondition){
        throw new BizException(...);
    }
    // ...
}

@Transactional
public void bar(){ // only add an annotation
    anotherBarWithoutTransaction();
}

在我上面的例子中我会直接调用anotherBarWithoutTransaction。但不是很理想。

使用程序化事务管理方式显式创建新事务,例如

@Autowired
private TransactionTemplate transactionTemplate;

transactionTemplate.execute(new TransactionCallbackWithoutResult() {
   protected void doInTransactionWithoutResult(TransactionStatus status) {
       try {
           barService.bar();
       } catch (ApiException e) {
           logger.warn("call bar failed",e);
           status.setRollbackOnly();
       }
   }
});

<bean id="transactionTemplate"
      class="org.springframework.transaction.support.TransactionTemplate">
    <property name="propagationBehaviorName" value="PROPAGATION_REQUIRES_NEW"/>
    <property name="transactionManager" ref="txManager"/>
</bean>

参考:http://docs.spring.io/autorepo/docs/spring/4.2.x/spring-framework-reference/html/transaction.html#transaction-programmatic