1. 程式人生 > >資料庫事務隔離級別以及spring傳播屬性

資料庫事務隔離級別以及spring傳播屬性

資料庫事務隔離級別

資料庫有四種事務隔離級別

  • 讀未提交(Read uncommitted)
  • 讀已提交(Read committed)
  • 可重複讀(Repeatable read)
  • 序列化(Serializable)
    以上事務隔離級別依次遞增,但是效能依次遞減。
    mysql支援以上四種隔離級別,其預設是:可重複讀(Repeatable read)。
    oracle資料庫支援READ COMMITTED 和 SERIALIZABLE兩種。
    oracle和PostgreSQL預設是:讀已提交(Read committed)。

隔離級別詳解

以上四種隔離分別會出現以下問題

隔離級別髒讀不可重複讀幻讀
讀未提交(Read uncommitted)可能可能可能
讀已提交(Read committed)不可能可能可能
可重複讀(Repeatable read)不可能不可能可能
序列化(Serializable)不可能不可能不可能
  • 髒讀:
    T1修改資料後未提交之前,T2可以訪問修改後的資料。

  • 不可重複讀:
    T1:讀取userid=1的salary=1000;
    T2:將userid=1的salary改為2000並提交;
    T1:此時再次讀取userid=1的記錄,則讀取不到salary=1000了,這既是不可重複讀。

  • 幻讀:
    T1:select id=1,resultset=null,此時準備插入一條;

    T2:insert id=1 並提交;
    T1:insert id=1 ,報錯。
    在這種情況下,T1按照邏輯本來是預計成功的,但是卻報錯主鍵衝突,此時T1就產生了幻讀,彷彿看花眼出現幻象了一般。

  • 序列化:
    每個事務排隊執行。
    序列話為什麼不會出現幻讀?因為會鎖定索引。
    還是上面幻讀的例子,T1查詢的時候,因為是主鍵查詢,資料庫會自動給索引加上鎖(索引加鎖,與具體資料無關),所以T2的操作會失敗,T1的插入會成功。當然如果我們在可重複讀模式下,通過select for update 是也可以達到Serializable的效果。

Spring事務傳播特性

事務傳播特性是指,當多個方法形成一個呼叫鏈時,事務是如何傳播的(如A方法中呼叫了B方法,那麼事務是以哪種方式傳播給B)。

spring只提供事務管理器,其實現交給hibernate等其他框架;Spring定義了7中傳播行為(org.springframework.transaction包中的TransactionDefinition介面):

  • PROPAGATION_REQUIRED(spring預設):如果當前存在事務,則加入該事務;如果當前沒有事務,則建立一個新的事務。
  • PROPAGATION_SUPPORTS:如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續執行。
  • PROPAGATION_MANDATORY:如果當前存在事務,則加入該事務;如果當前沒有事務,則丟擲異常。
  • PROPAGATIONREQUIRESNEW:建立一個新的事務,如果當前存在事務,則把當前事務掛起。
  • PROPAGATIONNOTSUPPORTED:以非事務方式執行,如果當前存在事務,則把當前事務掛起。
  • PROPAGATION_NEVER:以非事務方式執行,如果當前存在事務,則丟擲異常。
  • PROPAGATIONNESTED:如果當前存在事務,則建立一個事務作為當前事務的巢狀事務來執行;如果當前沒有事務,則該取值等價於PROPAGATIONREQUIRED。
    以上七中傳播特性中,前六種屬於EJB,被spring引進;後一種是spring特有的。

spring事務隔離級別

  • ISOLATION_DEFAULT:使用後端資料庫預設的隔離級別。
  • ISOLATION_READ_UNCOMMITTED:允許讀取尚未提交的更改。可能導致髒讀、幻影讀或不可重複讀。
  • ISOLATION_READ_COMMITTED:允許從已經提交的併發事務讀取。可防止髒讀,但幻影讀和不可重複讀仍可能會發生。
  • ISOLATION_REPEATABLE_READ:對相同欄位的多次讀取的結果是一致的,除非資料被當前事務本身改變。可防止髒讀和不可重複讀,但幻讀仍可能發生。
  • ISOLATION_SERIALIZABLE:完全服從ACID的隔離級別,確保不發生髒讀、不可重複讀