1. 程式人生 > >資料庫的七種隔離級別

資料庫的七種隔離級別

前言

本文的主要內容來源於《A Critique of ANSI SQL Isolation Levels》,文中圖片同樣來自此篇論文。

ANSI SQL92標準規定了四種隔離級別,read uncommitted、read committed、repeatable read、serializable isolation。隨著資料庫的發展,這已經越來越跟不上資料庫的發展,不同廠家的資料庫在相同的隔離級別下,在細微處可能表現出不同的行為,比如同為read committed,oracle、DB2和sybase的表現行為就不同。

為了便於使用者甄別不同廠家的資料庫定義的級別及其行為模式之間的聯絡和區別,《A Critique of ANSI SQL Isolation Levels》這篇論文提出希望修改標準以正確區分不同廠家資料庫的行為。很可惜最後沒有成功。

ANSI標準

下圖是ANSI SQL標準規定的事務隔離級別和有害現象的關係。


ANSI標準規定了三種有害現象,髒讀、模糊讀(不可重複讀)、幻讀。並通過這三種有害現象區分出了不同的隔離級別。

髒讀: 讀到未提交事務修改的資料;

模糊讀(不可重複讀):事務在執行過程中兩次讀取同一部分資料,得到的結果不一致。

幻讀:事務在執行過程中,兩次執行同一條件的查詢語句,發現第二次讀的資料比第一次要多。

模糊讀(不可重複讀)和幻讀最大的區別就是模糊讀(不可重複讀)只需要鎖住已經讀過的資料就可以了,而幻讀需要對還不存在的資料(或者是尚未滿足條件的資料)做出預防。

多提一句,只有serializable isolation是完全符合ACID標準的,其他三種情況,都不能完全避免不一致的情況。

所有隔離級別

不同廠家的資料庫產品支援的隔離級別名稱略有不同;

SYBASE支援的隔離級別:degree 0(read uncommitted)、degree 1(read committed)、degree 2(repeatable read)、degree 3(serializable isolation);

ORACLE支援的隔離級別:read committed(consistent read)、serializable(snapshot isolation);

DB2支援的隔離級別:read uncommitted、cursor stability、read stability、repeatable read;

Postgresql支援的隔離級別:read committed(consistent read)、repeatable read(snapshot isolation)、serializable isolation(Serialaizable Snapshot Isolation);

SQL Server支援的隔離級別:read uncommitted、read committed snapshot 、read committed 、repeatable read、snapshot isolation、serializable isolation;

MySQL支援的隔離級別:read uncommitted、read committed(consistent read)、repeatable read(snapshot isolation)、serializable isolation;

上面的列表中,前面是資料庫產品中隔離級別的名字,括號內的是實際對應的隔離級別。隔離級別的細微差別主要是MVCC機制和鎖機制實現不同導致的,其中,

SQL Server既支援鎖機制,又支援MVCC機制,因此事實上實現了六種隔離級別;

MySQL既支援MVCC機制,又使用鎖機制實現了基於鎖機制的serializable isolation;

Postgresql使用SSI實現了serializable isolation,這個實現和傳統的通過鎖機制實現的serializable isolation是不同的,其主要區別在於傳統鎖機制是first-lock-win,沒有拿到鎖的事務會等待,而PG的SSI機制是first-commit-win,後提交的不符合序列化要求的序列化事務會報錯回滾,而且SSI機制會導致一定的誤回滾,不過SSI機制是無阻塞的。

隔離級別之間的關係


1,四個基本的事務隔離級別就不多說了,和之前是一樣的。

2,Consistent Read和read committed之間的區別主要在cursor,Consisten Read的cursor無論資料如何修改,讀到的資料是不會改變的,即使修改資料的事務已經提交,而Read Committed級別的事務會讀到提交事務修改後的資料,DB2的Cursor Stability通過對cursor掃過的資料加鎖,實現了同樣的功能,但因為會產生阻塞,所以效能不如Consistent Read。

Consistent Read還有一個重要的優點,就是如果存在一個修改資料的事務在一個長查詢(select)內啟動並提交,那麼處於Read Committed和Cursor Stability級別的長查詢可能既讀到事務修改之前的資料,又讀到事務修改之後的資料,這對很多聚集函式有很嚴重的傷害。Consistent Read通過快照(snapshot)可以嚴格保證僅僅讀到語句開始前提交的事務修改過的資料。 3,Snapshot Isolation遮蔽了髒讀,模糊讀(不可重複讀),幻讀,但是仍然不是序列化隔離級別。如下 Tx1: update test1 set id=id+1; select * from test2; Tx2 update test2 set id=id+1;  select * from test1; 這兩個事務如果均在snapshot isolation下,並且並行執行,因為R(tx1)<W(tx2),R(tx2)<W(tx1),所以無論如何不能等等價成一個序列的執行順序,這在對資料一致性要求嚴格的場景下可能會造成很大問題,比如銀行。 4,Repeatable Read不會發生如上(3)的不一致情況,但無法遮蔽幻讀,它和Snapshot Isolation各有處理不了的情況,通常而言,從ANSI SQL92的標準來看,還是Snapshot Isolation更通用一些。

附表:

identifier query phenomena
P0 w1[x]...w2[x]...((c1 or a1) and (c2 or a2) in any order) Dirty Write
P1 w1[x]...r2[x]...((c1 or a1) and (c2 or a2) in any order) Dirty Read
P2 r1[x]...w2[x]...((c1 or a1) and (c2 or a2) any order) Fuzzy / Non-Repeatable Read
P3 r1[P]...w2[y in P]...((c1 or a1) and (c2 or a2) any order) Phantom
P4 r1[x]...w2[x]...w1[x]...c1 Lost Update
P4C rc1[x]...w2[x]...w1[x]...c1 Lost Update
A3 r1[P]...w2[y in P]...c2....r1[P]...c1 Phantom
A5A r1[x]...w2[x]...w2[y]...c2...r1[y]...(c1 or a1) Read Skew
A5B r1[x]...r2[y]...w1[y]...w2[x]...(c1 and c2 occur) Write Skew

附圖


因水平有限,不足之處請多多指正。