spring事務傳播機制

一隻小小狗發表於2020-12-17


1.事務傳播是什麼?

	假如有A,B兩個方法,方法A有事務,方法B無事務。這時,用呼叫方法A而方法A會呼叫方
法B,無事務方法B就會對A產生影響,相反事務方法A也會對B產生影響。這種影響具體是什麼
就由兩個方法所定義的事務傳播型別所決定。

在這裡插入圖片描述

2.事務傳播型別列舉Propagation

閱讀原始碼,和英文註釋可知:

事務傳播型別有7種
	REQUIRED、
	SUPPORTS、
	MANDATORY、
	REQUIRES_NEW、
	NOT_SUPPORTED、
	NEVER、
	NESTED。

也就是說列舉類Propagation是為了結合@Transactional註解使用而設計的,這個列舉裡面定義的事務傳播行為型別與TransactionDefinition中定義的事務傳播行為型別是對應的,所以在使用@Transactional註解時我們就要使用Propagation列舉類來指定傳播行為型別,而不直接使用TransactionDefinition介面裡定義的屬性。

//Propagation為了結合@Transactional使用而設計的
//而TransactionDefinition介面定義的事務傳播行為與Propagation列舉對應,
//使用Propagation類,而不直接使用TransactionDefinition介面
package org.springframework.transaction.annotation;
import org.springframework.transaction.TransactionDefinition;
public enum Propagation {
    ...
}

3.七種事務傳播行為,案例理解

首先我們為事務傳播設計一個案例,比如我要錄入一個商品,加入商品的圖片。

//業務層中
public void goods(Goods a){
	insertGoods(a);
}
public void img(Img b){
	insertImg(b);
}
//測試層中
public void testA(){
    goods(a);  //新增商品a
    testB();   //呼叫testB
}

public void testB(){
    img(b1);  //新增圖片b1
    new throw Exception;     //發生異常丟擲
    img(b2);  //新增圖片b2
}

①REQUIRED(Spring預設傳播事務)

 Support a current transaction, create a new one if none exists.
 支援當前事務,如果沒有事務就建立一個新事務。

情況1

//測試層中
@Transactional(propagation = Propagation.REQUIRED)
public void testA(){
    goods(a);  //新增商品a
    testB();   //呼叫testB
}

@Transactional(propagation = Propagation.REQUIRED)
public void testB(){
    img(b1);  //新增圖片b1
    new throw Exception;     //發生異常丟擲
    img(b2);  //新增圖片b2
}

沒有任何資料被錄入,假如testA中沒有事務,那麼就建立一個新的事務,由於呼叫了testB,所以沿用當前事務,丟擲異常時,回滾當前事務,沒有任何資料被錄入。

情況2

//測試層中
public void testA(){
    goods(a);  //新增商品a
    testB();   //呼叫testB
}

@Transactional(propagation = Propagation.REQUIRED)
public void testB(){
    img(b1);  //新增圖片b1
    new throw Exception;     //發生異常丟擲
    img(b2);  //新增圖片b2
}

商品本身被錄入,testA無事務,所有會被忽略,不會出現回滾,而testB中的事務,會因為丟擲異常而被回滾。

②SUPPORTS

Support a current transaction, throw an exception if none exists.
支援當前事務,如果不存在則丟擲異常(無事務就以無事務的方式處理)
//測試層中
public void testA(){
    goods(a);  //新增商品a
    testB();   //呼叫testB
}

@Transactional(propagation = Propagation.SUPPORTS)
public void testB(){
    img(b1);  //新增圖片b1
    new throw Exception;     //發生異常丟擲
    img(b2);  //新增圖片b2
}

商品a和圖片b1被錄入,testA中無事務所以直接插入,testB延續A的無事務狀態,遇見異常後b2不執行,所以只錄入了商品a和圖片b1.

③MANDATORY

Support a current transaction, throw an exception if none exists.
支援當前事務,如果不存在則丟擲異常
//測試層中
public void testA(){
    goods(a);  //新增商品a
    testB();   //呼叫testB
}

@Transactional(propagation = Propagation.MANDATORY)
public void testB(){
    img(b1);  //新增圖片b1
    new throw Exception;     //發生異常丟擲
    img(b2);  //新增圖片b2
}

只有商品a被錄入,testA無事務所有被錄入,而testB中由於沒有事務,但是遇見了異常就會全部回滾。

④REQUIRES_NEW

Create a new transaction, and suspend the current transaction if one exists.
建立一個事務,如果不存在,就掛起該事務
//測試層中
@Transactional(propagation = Propagation.REQUIRED)
public void testA(){
    goods(a);  //新增商品a
    testB();   //呼叫testB
    new throw Exception;     //發生異常丟擲
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void testB(){
    img(b1);  //新增圖片b1
    img(b2);  //新增圖片b2
}

只儲存了圖片b1和b2,在執行testB會開啟一個新事務,而testA發生的異常會回滾testA中的資料,所以商品a沒有儲存。
如果將testA和testB都設定成REQUIRED,那麼所有資料都會回滾不會儲存,因為他們都是一個事務下的,資料都會回滾

⑤NOT_SUPPORTED

Execute non-transactionally, suspend the current transaction if one exists.
以非事務方式執行,如果當前事務存在,則掛起當前事務。
//測試層中
@Transactional(propagation = Propagation.REQUIRED)
public void testA(){
    goods(a);  //新增商品a
    testB();   //呼叫testB
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void testB(){
    img(b1);  //新增圖片b1
    new throw Exception;     //發生異常丟擲
    img(b2);  //新增圖片b2
}

只有圖片b1錄入,testA執行,當testB執行時,將testA事務掛起,直接錄入了圖片b1,但是丟擲異常b2未執行。而testA事務出現異常,開始回滾。

⑥NEVER

Execute non-transactionally, throw an exception if a transaction exists	
不使用事務,如果當前事務存在,則丟擲異常
很容易理解,就是我這個方法不使用事務,並且呼叫我的方法也不允許有事務,如果呼叫我的方法有事務則我直接丟擲異常。
//測試層中
@Transactional(propagation = Propagation.REQUIRED)
public void testA(){
    goods(a);  //新增商品a
    testB();   //呼叫testB
}

@Transactional(propagation = Propagation.NEVER)
public void testB(){
    img(b1);  //新增圖片b1
    img(b2);  //新增圖片b2
}

沒有任何資料錄入,由於testA有事務,呼叫了沒有不允許使用事務的testB,直接丟擲異常。

⑦NESTED

Execute within a nested transaction if a current transaction exists
如果當前事物存在,則巢狀在事務中執行。否則REQUIRED的操作一樣(開啟一個事務)

情況1

//測試層中
@Transactional(propagation = Propagation.REQUIRED)
public void testA(){
    goods(a);  //新增商品a
    testB();   //呼叫testB
    new throw Exception; //丟擲異常
}

@Transactional(propagation = Propagation.NESTED)
public void testB(){
    img(b1);  //新增圖片b1
    img(b2);  //新增圖片b2
}

資料都不會錄入,因為在testMain發生異常時,父事務回滾則子事務也跟著回滾了

情況2

//測試層中
@Transactional(propagation = Propagation.REQUIRED)
public void testA(){
    goods(a);  //新增商品a
    try{
        testB();    //呼叫testB
    }catch(Exception e){

    }
    goods(a2);   //呼叫testB
}

@Transactional(propagation = Propagation.NESTED)
public void testB(){
    img(b1);  //新增圖片b1
    new throw Exception; //丟擲異常
    img(b2);  //新增圖片b2
}

只有商品a和a2錄入,因為testA事務捕獲了異常,testA會正常執行,而testB巢狀中丟擲異常會只回滾testB。

相關文章