zhuguowei
zhuguowei

Reputation: 8477

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(...);
    }
    // ...
}

if bar throw BizException , even in foo explicitly catch the exception, at final it still rollback and throw below exception

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)

And there are some solutions but I found it's not workable for my situation

e.g.

@Transactional(noRollbackFor=BizException.class)

because in foo also throw BizException and in this case it should be rollback.

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

If explicitly specify propagation is REQUIRES_NEW, when call bar() it will create a new session, and only rollback this session. But it exist other scenarios if bar failed all process will rollback.

So now my temporary solution is

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

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

In my above case I will directly call anotherBarWithoutTransaction. But it's not very ideal.

Upvotes: 0

Views: 793

Answers (1)

zhuguowei
zhuguowei

Reputation: 8477

Use programmatic transaction management way to explicitly create a new transaction, e.g.

@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>

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

Upvotes: 1

Related Questions