淺析Spring 事務(二十一) spring事務的傳播行為
阿新 • • 發佈:2018-12-25
經過我們上面一個章節的初步瞭解,我們已經知道了Spring事務的基本配置,今天我們一起接著討論一下spring事務的傳播
Spring是用列舉來表示事務傳播行為的,
package org.springframework.transaction.annotation; import org.springframework.transaction.TransactionDefinition; public enum Propagation { REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED), SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS), MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY), REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW), PPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED), NEVER(TransactionDefinition.PROPAGATION_NEVER), NESTED(TransactionDefinition.PROPAGATION_NESTED); private final int value; Propagation(int value) { this.value = value; } public int value() { return this.value; } }
Propagation.REQUIRED | 代表當前方法支援當前的事務,且與呼叫者處於同一事務上下文中,回滾統一回滾(如果當前方法是被其他方法呼叫的時候,且呼叫者本身即有事務),如果沒有事務,則自己新建事務, |
Propagation.SUPPORTS | 代表當前方法支援當前的事務,且與呼叫者處於同一事務上下文中,回滾統一回滾(如果當前方法是被其他方法呼叫的時候,且呼叫者本身即有事務),如果沒有事務,則該方法在非事務的上下文中執行 |
Propagation.MANDATORY | 代表當前方法支援當前的事務,且與呼叫者處於同一事務上下文中,回滾統一回滾(如果當前方法是被其他方法呼叫的時候,且呼叫者本身即有事務),如果沒有事務,則丟擲異常 |
Propagation.REQUIRES_NEW | 建立一個新的事務上下文,如果當前方法的呼叫者已經有了事務,則掛起呼叫者的事務,這兩個事務不處於同一上下文,如果各自發生異常,各自回滾 |
Propagation.NOT_SUPPORTED | 該方法以非事務的狀態執行,如果呼叫該方法的呼叫者有事務則先掛起呼叫者的事務 |
Propagation.NEVER | 該方法以非事務的狀態執行,如果呼叫者存在事務,則丟擲異常 |
Propagation.NESTED | 如果當前上下文中存在事務,則以巢狀事務執行該方法,也就說,這部分方法是外部方法的一部分,呼叫者回滾,則該方法回滾,但如果該方法自己發生異常,則自己回滾,不會影響外部事務,如果不存在事務,則與PROPAGATION_REQUIRED一樣,(其實這是資料庫帶有儲存點的事務的典型體現,舉例來說:旅遊行業來說,遊客從上海飛巴厘島,需要從香港進行轉機,那麼上海~香港就是一個方法且是一個事務,香港~巴厘島就是嵌入的方法,如果香港~巴厘島航班取消了,無需回滾上海~香港的,這樣代價太大,因為遊客已經到了香港,只需修改香港到巴厘島的航班就可以了,如果上海~香港的飛機取消了,則需要全部事務回滾,其實香港到巴厘島的航班沒有問題) |
好了,介紹了基本概念,我們還是實戰一下spring的傳播行為吧
我們接著上篇部落格的業務場景:
需求①:儲存使用者基本資訊即可,如果儲存使用者的詳細資訊發生異常不需要全部回滾,我們修改程式碼
UserDetailServiceImpl.java
UserServiceImpl.java
測試類:
package org.study.spring.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.study.spring.transaction.entity.Profession;
import org.study.spring.transaction.entity.User;
import org.study.spring.transaction.entity.UserDetail;
import org.study.spring.transaction.service.UserService;
public class SpringTransactionTest {
@Test
public void test1() throws IllegalAccessException{
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-transaction.xml");
UserService userBussinessServiceImpl = applicationContext.getBean("userServiceImpl",UserService.class);
userBussinessServiceImpl.saveUserAllInfo(new User("Ted",26), new UserDetail("[email protected]", "重慶高階公寓", "重慶大學"), new Profession("war3解說","電子競技"));
}
}
執行測試類,資料庫的結果是:
說明我們的設定成功了
②儲存使用者詳細資訊的時候,必須是在事務的上下文中執行,否則儲存使用者詳細資訊失敗
修改程式碼UserServiceImpl.java去掉事務
UserServiceImpl.java
執行測試類
失敗了,提示沒有檢測到事務上下文
我們再看看資料庫
我們可以看到使用者詳細資訊沒有儲存成功,雖然我們在儲存使用者詳細資訊的時候,程式碼層面並沒有發生任何異常,但依舊沒有儲存成功
③新來的實習生在寫儲存profession的模組時,沒有分清出not_support和never的區別,實習生是用never去管理,他的業務邏輯是覺得儲存職業資訊應該與主業務邏輯無關
程式碼修改如下:
ProfessionServiceImpl.java
UserServiceImpl.java
執行測試類
提示當前方法不應該在有事務的上下文中執行
我們修改一下ProfessionServiceImpl
順便我們修改一下測試類的測試資料
package org.study.spring.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.study.spring.transaction.entity.Profession;
import org.study.spring.transaction.entity.User;
import org.study.spring.transaction.entity.UserDetail;
import org.study.spring.transaction.service.UserService;
public class SpringTransactionTest {
@Test
public void test1() throws IllegalAccessException{
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-transaction.xml");
UserService userBussinessServiceImpl = applicationContext.getBean("userServiceImpl",UserService.class);
userBussinessServiceImpl.saveUserAllInfo(new User("Miss",26), new UserDetail("[email protected]", "上海浦東區", "上海大學"), new Profession("LOL解說","電子競技"));
}
}
執行測試類,顯示成功,資料庫資訊:
這樣就算正確的寫法了
好了,其他的用法大家自己去嘗試一下,根據自己真實的業務場景,spring的事務傳播行為在開發中佔據了很重要的地位~