事務處理之父Jim Gray對事務隔離性的定義:
Isolation: Concurrently executing transactions see the stored information as if they were running serially (one after another).
Read Uncommitted:最低的隔離級別,什么都不需要做,一個事務可以讀到另一個事務未提交的結果。所有的並發事務問題都會發生。
Read Committed:只有在事務提交后,其更新結果才會被其他事務看見。可以解決臟讀問題。
Repeated Read:在一個事務中,對於同一份數據的讀取結果總是相同的,無論是否有其他事務對這份數據進行操作,以及這個事務是否提交。可以解決臟讀、不可重復讀。
Serialization:事務串行化執行,隔離級別最高,犧牲了系統的並發性。可以解決並發事務的所有問題。
通常,在工程實踐中,為了性能的考慮會對隔離性進行折中。
1、 臟讀(Drity Read):事務A修改了一個數據,但未提交,事務B讀到了事務A未提交的更新結果,如果事務A提交失敗,事務B讀到的就是臟數據。
Read Committed可以解決臟讀問題,但仍存在以下兩種問題。
2、不可重復讀(Non-repeatable read) : 在同一個事務中,對於同一份數據讀取到的結果不一致。比如,事務B在事務A提交前讀到的結果,和提交后讀到的結果可能不同。不可重復讀出現的原因就是事務並發修改記錄,要避免這種情況,最簡單的方法就是對要修改的記錄加鎖,這導致鎖競爭加劇,影響性能。(另一種方法是通過MVCC可以在無鎖的情況下,避免不可重復讀。待了解。。)
Repeated Read可以解決不可重復讀問題和臟讀問題,但仍無法解決下面的問題。
3、幻讀(Phantom Read) : 在同一個事務中,同一個查詢多次返回的結果不一致。事務A新增了一條記錄,事務B在事務A提交前后各執行了一次查詢操作,發現后一次比前一次多了一條記錄。幻讀僅指由於並發事務增加記錄導致的問題,這個不能像不可重復讀通過記錄加鎖解決,因為對於新增的記錄根本無法加鎖。需要將事務串行化,才能避免幻讀。
通常來說,事務隔離級別越低,所需持有鎖的時間也就越短,並發性能也就越好。
MySQL數據庫的InnoDB存儲引擎是支持事務的引擎,其默認事務隔離級別為REPEATABLE READ(簡稱RR)。ANSI SQL標准下RR事務隔離級別是Degree 2.9999的隔離性,但是與ANSI SQL標准不同的是,InnoDB存儲引擎在RR的事務隔離級別下就解決了幻讀問題,從而實現Degree 3的隔離性要求,從而達到了真正隔離性的要求。對比其他數據庫,要達到真正的事務隔離性要求,必須將事務隔離級別設置為SERIALIZABLE。換句話說,MySQL InnoDB的默認事務隔離級別可以理解為其他數據庫的SERIABLIZABLE級別。
然而,從嚴格意義上來說,InnoDB的RR事務隔離級別的實現與傳統的SERIALIAZABLE事務隔離級別還是有些不一樣,這導致在某些特定場景下會給用戶有錯愕抑或不能接受的感覺,比如唯一索引列在一個事務中允許重復值存在。不過這並不會破壞事務的一致性,只要理解InnoDB存儲引擎的鎖與MVCC的實現,其實有些怪異的現象都好理解。
SNAPSHOT事務隔離級別
經典的SERIALIAZABLE事務隔離級別采用嚴格的兩階段鎖(strict two-phrase lock,簡稱:STPL)實現,這也是Jim Gray在書中提及的方法。但是由於讀寫都需要上鎖,這樣導致在大部分情況下事務的性能都不如類似RC(READ COMMITTED)這樣的事務隔離級別。
為了解決性能問題,最近越來越多的數據庫開始支持SNAPSHOT事務隔離級別(簡稱SI),如Oracle、PostgreSQL、Microsoft SQL Server數據庫等。SI事務隔離級別貌似解決了Dirty Read、Unrepeatable Read和Phantom Read問題。可惜的是,其依然不符合真正隔離性的要求,其存在write skew的異常問題。2008年的SIGMOD大會上,有人提出了Serializable Snapshot Isolation(SSI),從而解決了之前SI事務隔離級別存在的問題。PostgreSQL9.1版本在此論文基礎上實現了SSI事務隔離級別並做了相應的優化。此外,在2012年的VLDB大會上PostgreSQL發布了相應的論文,有興趣的讀者可以繼續研究。
基於快照的事務隔離級別(不論SI還是SSI)性能較之經典的SERIALIZABLE事務隔離級別提升非常多,但其存在兩個問題不容忽視。一是其會導致“錯誤”的回滾,因為其策略就是保證正確,雖然有時可能會誤殺一些沒有問題的事務。二是對於大事務的支持需要額外的內存保證,如果修改的數據量特別大,那么這可能會導致內存溢出的問題發生。但不論怎么說,SSI可能都是未來的一個默認事務隔離級別發展的方向。期待MySQL數據庫也能盡快支持。
參考:https://www.zhihu.com/question/31346392/answer/59815366、http://xm-king.iteye.com/blog/770721、http://www.tuicool.com/articles/ua6NJvb、https://www.zhihu.com/question/31346392/answer/51924208
