spring Transaction Propagation 事务传播
spring Transaction中有一個很重要的屬性:Propagation。主要用來配置當前需要執行的方法,與當前是否有transaction之間的關系。
我曉得有點兒抽象,這也是為什么我想要寫這篇博客的原因。看了后面的例子,大家應該就明白了。
一、Propagation取值:
REQUIRED(默認值):在有transaction狀態下執行;如當前沒有transaction,則創建新的transaction;
SUPPORTS:如當前有transaction,則在transaction狀態下執行;如果當前沒有transaction,在無transaction狀態下執行;
MANDATORY:必須在有transaction狀態下執行,如果當前沒有transaction,則拋出異常IllegalTransactionStateException;
REQUIRES_NEW:創建新的transaction并執行;如果當前已有transaction,則將當前transaction掛起;
NOT_SUPPORTED:在無transaction狀態下執行;如果當前已有transaction,則將當前transaction掛起;
NEVER:在無transaction狀態下執行;如果當前已有transaction,則拋出異常IllegalTransactionStateException。
二、REQUIRED與REQUIRED_NEW
上面描述的6種propagation屬性配置中,最難以理解,并且容易在transaction設計時出現問題的是REQUIRED和REQURED_NEW這兩者的區別。當程序在某些情況下拋出異常時,如果對于這兩者不夠了解,就可能很難發現而且解決問題。
下面我們給出三個場景進行分析:
場景一:
ServiceA.Java:
public class ServiceA {
@Transactional
public void callB() {
serviceB.doSomething();
}
}
ServiceB.java
public class ServiceB {
@Transactional
public void doSomething() {
throw new RuntimeException("B throw exception");
}
}
這種情況下,我們只需要在調用ServiceA.callB時捕獲ServiceB中拋出的運行時異常,則transaction就會正常的rollback。
場景二
在保持場景一中ServiceB不變,在ServiceA中調用ServiceB的doSomething時去捕獲這個異常,如下:
public class ServiceA {
@Transactional
public void callB() {
try {
serviceB.doSomething();
} catch (RuntimeException e) {
System.err.println(e.getMessage());
}
}
}
這個時候,我們再調用ServiceA的callB。程序會拋出org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only這樣一個異常信息。原因是什么呢?
因為在ServiceA和ServiceB中的@Transactional propagation都采用的默認值:REQUREID。根據我們前面講過的REQUIRED特性,當ServiceA調用ServiceB的時候,他們是處于同一個transaction中。如下圖所示:
當ServiceB中拋出了一個異常以后,ServiceB會把當前的transaction標記為需要rollback。但是ServiceA中捕獲了這個異常,并進行了處理,認為當前transaction應該正常commit。此時就出現了前后不一致,也就是因為這樣,拋出了前面的UnexpectedRollbackException。
場景三
在保持場景二中ServiceA不變,修改ServiceB中方法的propagation配置為REQUIRES_NEW,如下:
public class ServiceB {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void doSomething() {
throw new RuntimeException("B throw exception");
}
}
此時,程序可以正常的退出了,也沒有拋出UnexpectedRollbackException。原因是因為當ServiceA調用ServiceB時,serviceB的doSomething是在一個新的transaction中執行的。如下圖所示:
所以,當doSomething拋出異常以后,僅僅是把新創建的transaction rollback了,而不會影響到ServiceA的transaction。ServiceA就可以正常的進行commit。
當然這里把ServiceA和ServiceB放在兩個獨立的transaction是否成立,還需要再多多考慮你的業務需求。
轉載于:https://www.cnblogs.com/bendantuohai/p/5603356.html
總結
以上是生活随笔為你收集整理的spring Transaction Propagation 事务传播的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 软件简介
- 下一篇: 学习招投标相关知识-编写标书