如何只回滚内部方法而不影响外部方法?
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>
@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>