通過這篇文章,你將學習到Spring框架中中事務的傳遞
簡介
在處理Spring管理的事務時,開發人員可以以傳播的方式定義事務的行為。換句話說,開發人員能夠決定業務方法如何被封裝在邏輯和物理事務中。來自不同Spring bean的不同方法可以在相同的事務范圍或分割為多個嵌套的事務中執行。這可能導致像內部事務產生的結果如何影響外部事務的細節。我們將在下一節中看到Spring中不同的傳播機制的不同行為。
本教程將僅關注事務的傳播機制行為。Spring事務的其他方面的細節,你可以參考其他的教程或Spring官方文檔。
本教程所使用的完整代碼可以在教程的下方下載。我們將僅顯示Spring中幫助大家了解事務傳播機制相關部分。
完整的源代碼使用Hibernate實現持久層(Spring使用Hibernate的事務示例)。
表1事務傳播行為類型
事務傳播行為類型 |
說明 |
PROPAGATION_REQUIRED |
如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,加入到這個事務中。這是最常見的選擇。 |
PROPAGATION_SUPPORTS |
支持當前事務,如果當前沒有事務,就以非事務方式執行。 |
PROPAGATION_MANDATORY |
使用當前的事務,如果當前沒有事務,就拋出異常。 |
PROPAGATION_REQUIRES_NEW |
新建事務,如果當前存在事務,把當前事務掛起。 |
PROPAGATION_NOT_SUPPORTED |
以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。 |
PROPAGATION_NEVER |
以非事務方式執行,如果當前存在事務,則拋出異常。 |
PROPAGATION_NESTED |
如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行與PROPAGATION_REQUIRED類似的操作。 |
REQUIRED行為
Spring的REQUIRED行為意味著如果在當前bean方法執行的上下文中已存在打開的事務,則使用該事務;如果沒有已存在的事務,則Spring容器會創建新的事務并使用它。如果多個方法均配置為REQUIRED且調用為嵌套調用,那么它們會被劃分為多個邏輯的事務,但在底層使用相同物理事務。簡單來說,這意味著如果內層的方法引起了事務回滾,則外部的方法調用事務也會失敗同時回滾。讓我們看看一個示例:
外部Bean @Autowired private TestDAO testDAO; @Autowired private InnerBean innerBean; @Override @Transactional(propagation=Propagation.REQUIRED) public void testRequired(User user) { testDAO.insertUser(user); try{ innerBean.testRequired(); } catch(RuntimeException e){ // handle exception } } 內部Bean @Override @Transactional(propagation=Propagation.REQUIRED) public void testRequired() { throw new RuntimeException("Rollback this transaction!"); }
注意內部bean的方法使用了REQUIRED進行了注解并拋出了RuntimeException。這意味著它將于外部bean使用相同的事務,因此外部事務在提交時將失敗并同樣進行回滾操作。
注意:默認情況下,只有非受檢異常(unchecked exception),像RuntimeException,會將事務的狀態設置為回滾。如果你希望受檢異常(checked exception)也可以將事務狀態設置為回滾,你必須設置它們,但此內部不包含在本教程中。
注意2:當使用聲明式事務時(也就是通過使用注解形式),如果在相同的bean中直接調用方法(自己調用自己的方法),@Transactional注解將被容器忽略。如果你希望啟用自身方法調用的事務管理,你必須使用aspectj來配置事務,但是該內容不包含在本教程中。
REQUIRES_NEW行為
REQUIRES_NEW行為意味著容器將總會創建新的物理的事務,如果當前存在事務,把當前事務掛起。
外部 bean @Autowired private TestDAO testDAO; @Autowired private InnerBean innerBean; @Override @Transactional(propagation=Propagation.REQUIRED) public void testRequiresNew(User user) { testDAO.insertUser(user); try{ innerBean.testRequiresNew(); } catch(RuntimeException e){ // handle exception } } 內部 bean @Override @Transactional(propagation=Propagation.REQUIRES_NEW) public void testRequiresNew() { throw new RuntimeException("Rollback this transaction!"); }
內部方法使用REQUIREDS_NEW進行注解,并拋出RuntimeException,因此它的事務會回滾但是不會影響到外部的事務。外部事務在內部事務啟動時將被掛起然后在內部事務處理完畢后恢復。它們獨立的進行處理因此外部的事務也會成功的提交。
NETSTED行為
NESTED行為使用相同的物理事務但是在嵌套調用時設置了保留點(savepoint),因此內部的事務可以獨立于外部事務回滾而不影響外部事務。這個可能與JDBC的savepoint比較類似,因此該行為需要與Spring的JDBC管理的事務一起使用(Spring JDBC 事務例子).
MANDATORY行為
MANDATORY行為要求執行該方法時,必須有一個已存在且打開的事務。如果沒有已存在的事務,容器會拋出異常。
NEVER行為
NEVER行為要求執行該方法時,不能有已存在的事務。如果事務已存在,那么容器將會拋出異常。
NOT_SUPPORTED行為
NOT_SUPPORTED行為標示在執行方法時,將忽略事務。如果已存在打開的事務,則該事務會被掛起。
SUPPORTS行為
SUPPORTS行為標示在執行方法時,如果存在事務,則在事務范圍執行,如果不存在,則不以事務方式執行。
完整的筆記源碼
本頁尾有完整的代碼下載。下面是 MySQL 建表語句:
MySQL 建表語句
CREATE TABLE USER ( ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, USERNAME VARCHAR (32) NOT NULL, NAME VARCHAR (64) NOT NULL, UNIQUE (USERNAME) );
下載本教程源碼
下載鏈接: spring-transaction-propagation-tutorial.zip
相關:
事務的傳播行為(講得比較好)
文章列表