1. 程式人生 > >淺析Spring 事務(二十一) spring事務的傳播行為

淺析Spring 事務(二十一) spring事務的傳播行為

經過我們上面一個章節的初步瞭解,我們已經知道了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的事務傳播行為在開發中佔據了很重要的地位~