3 回答

TA貢獻1820條經驗 獲得超10個贊
就您的示例而言,如果inner()有:
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void inner(){
//some logic
}
然后,如果它在outer()循環中的第二個調用中拋出異常,則第一個調用中的更改將已經提交 - 由其REQUIRES_NEW.
如果inner()有:
@Transactional(propagation=Propagation.NESTED)
public void inner(){
//some logic
}
然后將回滾第一次調用的更改 - 因為outer().
傳播級別inner()真正開始重要的一點是outer()循環是否要處理以下異常inner():
@Transactional
public void outer() {
for (int i = 0; i < 100500; i++) {
try {
inner();
} catch (Exception ex) {
// Report and continue
}
}
// Something else that could fail
}
顯然,兩者REQUIRES_NEW并NESTED只保留從成功改變inner()通話。但關鍵的區別在于,NESTED如果outer().
正如您所說,另一個因素是可擴展性 - 某些數據庫可能不會通過NESTED傳播來理解父事務的大小。
此外,這可能值得一提——盡管我懷疑它只是為了讓示例更加清晰。this.inner()直接調用是繞過 Spring 事務顧問程序。它需要被允許注入一個“被建議的 bean”,以允許@Transactional注釋在調用之前和之后發揮它的魔力——例如nextAutowiredBean.inner()。

TA貢獻1876條經驗 獲得超7個贊
我看到的最大差異:
在嵌套的情況下:
如果外部事務回滾,則嵌套的 tra 也會回滾。
可見性:如果數據庫同時執行非常常見的 MVCC,
嵌套的 tra 會看到外部 tra 的先前更改。
在外部提交后,嵌套 tra 的更改將被提交,并且對其他 tra 可見。
性能:請注意,外部事務的工作集會被內部事務擴展。所以更多的鎖,更多的 MVCC 原像存儲,更長的重做日志條目。
在 requires_new 的情況下:
如果外層事務回滾,則外層tra回滾的情況下,內層tra的變化不會回滾。
可見性:對于同時非常常見的 MVCC,
內部 tra 不會看到尚未提交的外部 tra 所做的更改。
在這個內部 tra 提交之后,甚至在外部 tra 提交之前,嵌套 tra 的更改將被提交并立即對其他 tra 可見。鎖更少,但由于提交更多的外部操作,redo-lock 中的記錄更多。
在性能方面,如果其他因素不重要,您可以在交易大小和交易數量之間找到收支平衡。如果嵌套的速度比 requires_new 快,那么這個問題沒有通用的答案。

TA貢獻1853條經驗 獲得超6個贊
如果您的內部邏輯獨立于外部邏輯,則使用 Requires_new,如果不使用嵌套。
例如,您的外部方法可能正在處理包含大量記錄的作業并調用保持作業狀態(進度、警告和驗證錯誤)的內部方法。您希望內部方法事務是獨立的,并且它的數據庫更改會立即保存,以便系統的其他部分可以顯示進度。如果外部方法遇到異常,它的事務會回滾,但內部方法的事務不會。
當您需要將外部和內部更改同時保留或同時回滾時,您可能希望使用嵌套或依賴事務。例如,您需要創建一個新用戶(使用“外部”服務)并保存他們的地址(使用“內部”服務)。如果您的要求是用戶必須有一個地址,那么如果保存用戶或地址失敗,您希望這兩個更改都回滾。
添加回答
舉報