天天看點

資料庫的事務隔離級别的基礎知識

1、  ANSI SQL給出了四種标準的事務隔離級别:可序列化(Serializable)、可重複讀(Repeatable reads)、送出讀(Read committed)和未送出讀(Read uncommitted)。

還有一個Snapshot的概念。

2、  隔離級别隻會影響讀操作申請的共享鎖,而不會影響寫操作的互斥鎖。

3、  隔離級别影響讀事務的行為:

1)  否使用共享鎖,以哪種隔離級别來隔離。

2)   事務持有讀鎖的時間

3)  在有其他更新事務進行資料操作時,如何執行讀的操作。

l  被阻塞,等待其他事務釋放互斥鎖

l  讀取事務送出後的版本,該資料行在事務開始時存在

l  讀沒有送出的資料

下面介紹不同隔離級别下的差異

4、  隔離級别:ReadCommitted(意思是隻能讀到Commited的資料)

大多數資料庫預設的隔離模式(有說MySQL不是,不知指哪個存儲引擎)。在事務完成送出之前,其他事務看不到該事務的修改結果。但可能的是:如果一個事務A中讀2次資料。而在此中間,有另外事務B修改相關資料并送出,則在A的兩次讀中,值不一樣。是以也叫做不可重複讀。但確定的讀到的資料,一定是Commit的。

這裡還加上Snapshot後,行為有不同。

1)  如果Snapshot為OFF,讀操作申請共享鎖,阻塞其他事務的寫操作。一旦讀操作完成,釋放共享鎖。

2)  如果Snapshot為ON,讀操作時使用RowVersioning(這實際就是Snapshot的概念),就是有多副本,寫操作不阻塞讀操作,是以不會申請共享鎖,不會阻塞其他事務的寫操作。

5、  在ReadunCommited下

1)  讀操作不會申請SharedLock。是以讀操作不會阻塞寫操作。事務中的修改及時沒送出也會被其他事務可見,這樣會産生髒讀,如果事務失敗復原,則其他事務之前的到的資料則是髒資料。從性能上講,不會别别的事務提高太多,但是極其不安全。

6、  在Repeatablereads下

事務A讀取與搜尋條件相比對的若幹行。事務B以插入或删除行等方式來修改事務A的結果集,然後再送出。事務A再讀取時,卻發現資料發生了變化。造成了幻讀。(MySQL預設的隔離級别)。

另一種更好了解:事務在執行過程中可以看到其他事務已送出的新插入記錄,但不能看到其他事務已送出的對已有記錄的更新。

7、  在Serializable下

是最高的事務隔離級别,同時代價也花費最高,性能很低,一般很少使用,在該級别下,事務順序執行,不僅可以避免髒讀、不可重複讀,還避免了幻讀。

在Snapshot隔離級别下,事務在修改任何資料之前,先将修改前的資料複制到tempdb,寫操作建立資料行的一個原始版本(Row Version)。後續其他事務的一切讀操作都去讀這個複制的行版本。在Snapshot隔離級别下,讀寫操作不會互相阻塞。使用行版本控制提高事務的并發性,但是有一個明顯的缺點,雖然使用者讀到的不是髒資料,但是資料可能正在被修改,很快就要過期。如果根據這個過期的資料做資料修改,可能會産生邏輯錯誤。

參考:

1、《資料庫的快照隔離級别(Snapshot Isolation)》https://www.cnblogs.com/ljhdo/p/5037033.html