框架采用的是spring管理聲明式事務(wù),這幾天業(yè)務(wù)開發(fā)時(shí)遇到了點(diǎn)麻煩,記錄下備忘。
場(chǎng)景:在Service類中使用子事務(wù)(saveponit)時(shí),當(dāng)子事務(wù)拋出異常后,此異常處理掉不繼續(xù)往外拋,spring在提交主事務(wù)時(shí)會(huì)拋出
org.springframework.transaction.UnexpectedRollbackException: Transaction has been rolled back because it has been marked as rollback
方法調(diào)用結(jié)構(gòu):
假若有A、B、C三個(gè)Service類,其實(shí)例對(duì)象分別為a、b、c,類分別定義如下:
A {
方法() { //propagation="REQUIRED"
try{
b.方法();
} catch (Exception e) {
}
}
}
B{
savePoint方法() { //propagation="NESTED"
c.方法(); //如果這里邊的操作全是普通類(不是Service類)操作,不會(huì)有問(wèn)題。
}
}
C{
方法() { //propagation="REQUIRED"
throw new Exception("出錯(cuò)");
}
}
通過(guò)調(diào)試spring源碼
......
Getting transaction for [A.方法] .....
......
Creating nested transaction with name [B.savePoint方法]........
......
Participating in existing transaction
Getting transaction for [C.方法]
........
Participating transaction failed - marking existing transaction as rollback-only
//此時(shí),已把主事務(wù)標(biāo)記成了rollback-only
所以,當(dāng)在a.方法完成時(shí)提交事務(wù)時(shí)會(huì)報(bào)Transaction has been rolled back because it has been marked as rollback錯(cuò)誤。
認(rèn)真的您可能會(huì)發(fā)現(xiàn),在 org.springframework.transaction.support.AbstractPlatformTransactionManager 中有個(gè)叫
isGlobalRollbackOnParticipationFailure的參數(shù),默認(rèn)是true.
源碼中說(shuō)明:
Switch this to "false" to let the transaction originator make the rollback decision. If a participating transaction fails with an exception, the caller can still decide to continue with a different path within the transaction. However, note that this will only work as long as all participating resources are capable of continuing towards a transaction commit even after a data access failure: This is generally not the case for a Hibernate Session, for example; neither is it for a sequence of JDBC insert/update/delete operations.
大意是:如果isGlobalRollbackOnParticipationFailure為false,則會(huì)讓主事務(wù)決定回滾,如果當(dāng)遇到exception加入事務(wù)失敗時(shí),調(diào)用者能繼續(xù)在事務(wù)內(nèi)決定是回滾還是繼續(xù)。然而,要注意是那樣做僅僅適用于在數(shù)據(jù)訪問(wèn)失敗的情況下且只要所有操作事務(wù)能提交。
初步解決方案:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> <property name="globalRollbackOnParticipationFailure" value="false" /> <!--指定此參數(shù)為false-->
</bean>
經(jīng)測(cè)試,此問(wèn)題暫時(shí)得到解決,不知道會(huì)不會(huì)引起其它問(wèn)題,至少目前還沒有發(fā)現(xiàn)其它異常。您若通過(guò)此方案解決之后出現(xiàn)了新的問(wèn)題請(qǐng)留信回復(fù),我們一起交流,非常感謝!