天天看點

Spring事務配置的五種方式和spring裡面事務的傳播屬性和事務隔離級别

spring事務配置的五種方式:

前段時間對spring的事務配置做了比較深入的研究,在此之間對spring的事務配置雖說也配置過,但是一直沒有一個清楚的認識。通過這次的學習發覺spring的事務配置隻要把思路理清,還是比較好掌握的。

總結如下:

spring配置檔案中關于事務配置總是由三個組成部分,分别是datasource、transactionmanager和代理機制這三部分,無論哪種配置方式,一般變化的隻是代理機制這部分。

datasource、transactionmanager這兩部分隻是會根據資料通路方式有所變化,比如使用hibernate進行資料通路時,datasource實際為sessionfactory,transactionmanager的實作為hibernatetransactionmanager。

具體如下圖:

Spring事務配置的五種方式和spring裡面事務的傳播屬性和事務隔離級别

根據代理機制的不同,總結了五種spring事務的配置方式,配置檔案如下:

第一種方式:每個bean都有一個代理

第二種方式:所有bean共享一個代理基類

第三種方式:使用攔截器

第四種方式:使用tx标簽配置的攔截器

第五種方式:全注解

此時在dao上需加上@transactional注解,如下:

spring裡面事務的傳播屬性和事務隔離級别:

一、propagation (事務的傳播屬性)

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

propagation_required --支援目前事務,如果目前沒有事務,就建立一個事務。這是最常見的選擇。

propagation_supports --支援目前事務,如果目前沒有事務,就以非事務方式執行。

propagation_mandatory--支援目前事務,如果目前沒有事務,就抛出異常。

propagation_requires_new --建立事務,如果目前存在事務,把目前事務挂起。

propagation_not_supported --以非事務方式執行操作,如果目前存在事務,就把目前事務挂起。

propagation_never --以非事務方式執行,如果目前存在事務,則抛出異常。

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。

也就是說serviceb.methodb失敗復原,那麼servicea.methoda也會復原到savepoint點上,servicea.methoda可以選擇另外一個分支,比如servicec.methodc,繼續執行,來嘗試完成自己的事務。但是這個事務并沒有在ejb标準中定義。

二、isolation level(事務隔離等級):

1、serializable:最嚴格的級别,事務串行執行,資源消耗最大;

2、repeatable read:保證了一個事務不會修改已經由另一個事務讀取但未送出(復原)的資料。避免了“髒讀取”和“不可重複讀取”的情況,但是帶來了更多的性能損失。

3、read committed:大多數主流資料庫的預設事務等級,保證了一個事務不會讀到另一個并行事務已修改但未送出的資料,避免了“髒讀取”。該級别适用于大多數系統。

4、read uncommitted:保證了讀取過程中不會讀取到非法資料。隔離級别在于處理多事務的并發問題。

我們知道并行可以提高資料庫的吞吐量和效率,但是并不是所有的并發事務都可以并發運作,這需要檢視資料庫教材的可串行化條件判斷了。這裡就不闡述。

我們首先說并發中可能發生的3中不讨人喜歡的事情

1: dirty reads --讀髒資料。也就是說,比如事務a的未送出(還依然緩存)的資料被事務b讀走,如果事務a失敗復原,會導緻事務b所讀取的的資料是錯誤的。

2: non-repeatable reads --資料不可重複讀。比如事務a中兩處讀取資料-total-的值。在第一讀的時候,total是100,然後事務b就把total的資料改成 200,事務a再讀一次,結果就發現,total竟然就變成200了,造成事務a資料混亂。

3: phantom reads --幻象讀資料,這個和non-repeatable reads相似,也是同一個事務中多次讀不一緻的問題。但是non-repeatable reads的不一緻是因為他所要取的資料集被改變了(比如total的資料),但是phantom reads所要讀的資料的不一緻卻不是他所要讀的資料集改變,而是他的條件資料集改變。比如select account.id

where account.name="ppgogo*",第一次讀去了6個符合條件的id,第二次讀取的時候,由于事務b把一個帳号的名字由"dd"改成"ppgogo1",結果取出來了7個資料。

dirty reads

non-repeatable reads

phantom reads

serializable

不會

repeatable read

read committed

read uncommitted

三、readonly

事務屬性中的readonly标志表示對應的事務應該被最優化為隻讀事務。

這是一個最優化提示。在一些情況下,一些事務政策能夠起到顯著的最優化效果,例如在使用object/relational映射工具(如:hibernate或toplink)時避免dirty checking(試圖“重新整理”)。

四、timeout

在事務屬性中還有定義“timeout”值的選項,指定事務逾時為幾秒。在jta中,這将被簡單地傳遞到j2ee伺服器的事務協調程式,并據此得到相應的解釋

後續

資料庫提供了四種事務隔離級别, 不同的隔離級别采用不同的鎖類開來實作.

在四種隔離級别中, serializable的級别最高, read uncommited級别最低.

大多數資料庫的預設隔離級别為: read commited,如sql server , oracle.

少數資料庫預設的隔離級别為repeatable read, 如mysql innodb存儲引擎

即使是最低的級别,也不會出現 第一類 丢失 更新問題 .

1. 髒讀(事務沒送出,提前讀取) :

髒讀就是指當一個事務正在通路資料,并且對資料進行了修改,而這種修改還沒有送出到資料庫中,這時,另外一個事務也通路這個資料,然後使用了這個資料。

2. 不可重複讀(兩次讀的不一緻) :

是指在一個事務内,多次讀同一資料。在這個事務還沒有結束時,另外一個事務也通路該同一資料。那麼,在第一個事務中的兩次讀資料之間,由于第二個事務的修改,那麼第一個事務兩次讀到的的資料可能是不一樣的。這樣就發生了在一個事務内兩次讀到的資料是不一樣的,是以稱為是不可重複讀。例如,一個編輯人員兩次讀取同一文檔,但在兩次讀取之間,作者重寫了該文檔。當編輯人員第二次讀取文檔時,文檔已更改。原始讀取不可重複。如果隻有在作者全部完成編寫後編輯人員才可以讀取文檔,則可以避免該問題。

3. 幻讀 :

是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的資料進行了修改,這種修改涉及到表中的全部資料行。同時,第二個事務也修改這個表中的資料,這種修改是向表中插入一行新資料。那麼,以後就會發生操作第一個事務的使用者發現表中還有沒有修改的資料行,就好象發生了幻覺一樣。例如,一個編輯人員更改作者送出的文檔,但當生産部門将其更改内容合并到該文檔的主複本時,發現作者已将未編輯的新材料添加到該文檔中。如果在編輯人員和生産部門完成對原始文檔的處理之前,任何人都不能将新材料添加到文檔中,則可以避免該問題。

4. 第一類更新丢失(復原丢失) :

當2個事務更新相同的資料源,如果第一個事務被送出,而另外一個事務卻被撤銷,那麼會連同第一個事務所做的跟新也被撤銷。也就是說第一個事務做的跟新丢失了。

5. 第二類更新丢失(覆寫丢失) :

第二類更新丢失實在實際應用中經常遇到的并發問題,他和不可重複讀本質上是同一類并發問題,通常他被看做不可重複讀的特例:當2個或這個多個事務查詢同樣的記錄然後各自基于最初的查詢結果更新該行時,會造成第二類丢失更新。因為每個事務都不知道不知道其他事務的存在,最後一個事務對記錄做的修改将覆寫其他事務對該記錄做的已送出的跟新...

補充 : 基于中繼資料的 spring 聲明性事務 :

isolation 屬性一共支援五種事務設定,具體介紹如下:

default ——使用資料庫設定的隔離級别 ( 預設 ) ,由 dba 預設的設定來決定隔離級别 .

read_uncommitted ——會出現髒讀、不可重複讀、幻讀 ( 隔離級别最低,并發性能高 )

read_committed ——會出現不可重複讀、幻讀問題(鎖定正在讀取的行)

repeatable_read—— 會出幻讀(鎖定所讀取的所有行)

serializable ——保證所有的情況不會發生(鎖表)

不可重複讀的重點是修改 : 同樣的條件 , 你讀取過的資料 , 再次讀取出來發現值不一樣了

幻讀的重點在于新增或者删除 :同樣的條件 , 第 1 次和第 2 次讀出來的記錄數不一樣