
一、問題描述
事務的注解使用起來很簡單,但是如果只了解皮毛就會出現事務失效、事務異常等問題。
關于事務失效場景,我在這篇《為什么你的事務不好使?一下解決Java中N種事務失效場景》文章中記錄了多種失效場景,這里就不再贅述。
本次主要講,在事務嵌套(加了事務的方法,調用加了事務的方法)時,報錯
Transaction rolled back because it has been marked as rollback-only, org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
二、問題產生原因
2.1、問題復現
如下,在ClassA類中有個加了事務的A方法,調用了ClassB中的加了事務的B方法
public Class ClassA {
private ClassB classB;
@Transactional
public void A() {
try {
B();
} catch (Exception e) {
log.error("啥也不干");
}
}
}
public Class ClassB {
@Transactional
public void B() {
throw new Exception();
}
}
這種情況下就會報錯:Transaction rolled back because it has been marked as rollback-only
2.2、報錯原因
當A方法的事物(REQUIRED),B方法的事物(REQUIRED),A調用B方法,在spring中,spring將會把這些事務合二為一。
當整個方法中每個子方法沒報錯時,整個方法執行完才提交事務。
如果某個子方法有異常,spring將該事務標志為rollback only。如果這個子方法沒有將異常往上拋,或者主父方法將子方法拋出的異常捕獲了,那么,該異常就不會觸發事務進行回滾,事務就會在整個方法執行完后就會提交,這時就會造成Transaction rolled back because it has been marked as rollback-only的異常。(由于異常被標記了rollback only,但是又執行了commit,此時就會報這個錯)
三、解決方法
-
方法1:父方法不要捕獲異常
在2.1的舉例中,A方法去掉try…catch即可
-
方法2:子方法的事務propagation屬性換為NESTED
在2.1的舉例中,將B方法的事務注解的屬性改為NESTED
public Class ClassB { @Transactional(propagation = Propagation.NESTED) public void B() { throw new Exception(); } }
| 屬性 | 功能描述 |
|---|---|
| Propagation.NESTED | 表示如果當前已經存在一個事務,那么該方法將會在嵌套事務中運行。嵌套的事務可以獨立于當前事務進行單獨地提交或回滾。如果當前事務不存在,那么其行為和 Propagation.REQUIRED 效果一樣。 |
「喜歡這篇文章,您的關注和贊賞是給作者最好的鼓勵」
關注作者
【版權聲明】本文為墨天輪用戶原創內容,轉載時必須標注文章的來源(墨天輪),文章鏈接,文章作者等基本信息,否則作者和墨天輪有權追究責任。如果您發現墨天輪中有涉嫌抄襲或者侵權的內容,歡迎發送郵件至:contact@modb.pro進行舉報,并提供相關證據,一經查實,墨天輪將立刻刪除相關內容。




