1. 程式人生 > >spring的傳播屬性和隔離級別

spring的傳播屬性和隔離級別

在Spring中,主要是通過AOP來完成宣告式的事務管理。要了解Spring對事務的支援,首先要了解事務的屬性。在Spring中事務屬性主要分以下幾方面:

傳播行為(Propagation behavior)

Propagation:key屬性確定代理應該給哪個方法增加事務行為。這樣的屬性最重要的部份是傳播行為。有以下選項可供使用:

PROPAGATION_REQUIRED–支援當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。

PROPAGATION_SUPPORTS–支援當前事務,如果當前沒有事務,就以非事務方式執行。

PROPAGATION_MANDATORY–支援當前事務,如果當前沒有事務,就丟擲異常。

PROPAGATION_REQUIRES_NEW–新建事務,如果當前存在事務,把當前事務掛起。

PROPAGATION_NOT_SUPPORTED–以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。

PROPAGATION_NEVER–以非事務方式執行,如果當前存在事務,則丟擲異常。

PROPAGATION_NESTED:在一個嵌入的事務中進行。

1、PROPAGATION_REQUIRED加入當前正要執行的事務不在另外一個事務裡,那麼就起一個新的事務,比如說,ServiceB.methodB的事務級別定義為PROPAGATION_REQUIRED,那麼由於執行ServiceA.methodA的時候,ServiceA.methodA已經起了事務,這時呼叫ServiceB.methodB,ServiceB.methodB看到自己已經執行在ServiceA.methodA的事務內部,就不再起新的事務。而假如ServiceA.methodA執行的時候發現自己沒有在事務中,他就會為自己分配一個事務。這樣,在ServiceA.methodA或者在ServiceB.methodB內的任何地方出現異常,事務都會被回滾。即使ServiceB.methodB的事務已經被提交,但是ServiceA.methodA在接下來fail要回滾,ServiceB.methodB也要回滾。

2、PROPAGATION_SUPPORTS
如果當前在事務中,即以事務的形式執行,如果當前不再一個事務中,那麼就以非事務的形式執行。

3、PROPAGATION_MANDATORY
必須在一個事務中執行。也就是說,他只能被一個父事務呼叫。否則,他就要丟擲異常。

4、PROPAGATION_REQUIRES_NEW
這個就比較繞口了。 比如我們設計ServiceA.methodA的事務級別為PROPAGATION_REQUIRED,ServiceB.methodB的事務級別為PROPAGATION_REQUIRES_NEW,那麼當執行到ServiceB.methodB的時候,ServiceA.methodA所在的事務就會掛起,ServiceB.methodB會起一個新的事務,等待ServiceB.methodB的事務完成以後,他才繼續執行。他與PROPAGATION_REQUIRED 的事務區別在於事務的回滾程度了。因為ServiceB.methodB是新起一個事務,那麼就是存在兩個不同的事務。如果ServiceB.methodB已經提交,那麼ServiceA.methodA失敗回滾,ServiceB.methodB是不會回滾的。如果ServiceB.methodB失敗回滾,如果他丟擲的異常被ServiceA.methodA捕獲,ServiceA.methodA事務仍然可能提交。

5、 PROPAGATION_NOT_SUPPORTED
當前不支援事務。比如ServiceA.methodA的事務級別是PROPAGATION_REQUIRED ,而ServiceB.methodB的事務級別是PROPAGATION_NOT_SUPPORTED ,那麼當執行到ServiceB.methodB時,ServiceA.methodA的事務掛起,而他以非事務的狀態執行完,再繼續ServiceA.methodA的事務。

6、PROPAGATION_NEVER
不能在事務中執行。假設ServiceA.methodA的事務級別是PROPAGATION_REQUIRED,而ServiceB.methodB的事務級別是PROPAGATION_NEVER ,那麼ServiceB.methodB就要丟擲異常了。

7、 PROPAGATION_NESTED
理解Nested的關鍵是savepoint。他與PROPAGATION_REQUIRES_NEW的區別是,PROPAGATION_REQUIRES_NEW另起一個事務,將會與他的父事務相互獨立,而Nested的事務和他的父事務是相依的,他的提交是要等和他的父事務一塊提交的。也就是說,如果父事務最後回滾,他也要回滾的。而Nested事務的好處是他有一個savepoint。

    ServiceA {

    /**
    * 事務屬性配置為 PROPAGATION_REQUIRED
    */
    void methodA() {
    try {
    //savepoint
    ServiceB.methodB(); //PROPAGATION_NESTED 級別
    } catch (SomeException) {
    // 執行其他業務, 如 ServiceC.methodC();
    }
    }

    }

也就是說ServiceB.methodB失敗回滾,那麼ServiceA.methodA也會回滾到savepoint點上,ServiceA.methodA可以選擇另外一個分支,比如ServiceC.methodC,繼續執行,來嘗試完成自己的事務。但是這個事務並沒有在EJB標準中定義。

事務的隔離級別(Isolation level)

1、 ISOLATION_DEFAULT: 這是一個PlatfromTransactionManager預設的隔離級別,使用資料庫預設的事務隔離級別.另外四個與JDBC的隔離級別相對應

2、 ISOLATION_READ_UNCOMMITTED: 這是事務最低的隔離級別,它充許令外一個事務可以看到這個事務未提交的資料。這種隔離級別會產生髒讀,不可重複讀和幻像讀。

3、 ISOLATION_READ_COMMITTED: 保證一個事務修改的資料提交後才能被另外一個事務讀取。另外一個事務不能讀取該事務未提交的資料

4、 ISOLATION_REPEATABLE_READ: 這種事務隔離級別可以防止髒讀,不可重複讀。但是可能出現幻像讀。它除了保證一個事務不能讀取另一個事務未提交的資料外,還保證了避免下面的情況產生(不可重複讀)。

5、 ISOLATION_SERIALIZABLE 這是花費最高代價但是最可靠的事務隔離級別。事務被處理為順序執行。除了防止髒讀,不可重複讀外,還避免了幻像讀。

什麼是髒資料,髒讀,不可重複讀,幻覺讀?

1、Dirty read(髒讀): 指當一個事務正在訪問資料,並且對資料進行了修改,而這種修改還沒有提交到資料庫中,這時,另外一個事務也訪問這個資料,然後使用了這個資料。因為這個資料是還沒有提交的資料, 那麼另外一個事務讀到的這個資料是髒資料,依據髒資料所做的操作可能是不正確的。

2、Non-repeatable read(不可重複讀): 指在一個事務內,多次讀同一資料。在這個事務還沒有結束時,另外一個事務也訪問該同一資料。那麼,在第一個事務中的兩次讀資料之間,由於第二個事務的修改,那麼第一個事務兩次讀到的資料可能是不一樣的。這樣就發生了在一個事務內兩次讀到的資料是不一樣的,因此稱為是不可重複讀。

3、Phantom read(幻象讀): 指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的資料進行了修改,這種修改涉及到表中的全部資料行。同時,第二個事務也修改這個表中的資料,這種修改是向表中插入一行新資料。那麼,以後就會發生操作第一個事務的使用者發現表中還有沒有修改的資料行,就好象發生了幻覺一樣。