MYSQL如何解決幻讀


第一部分

首先要了解下mysql數據庫的事務特征之一隔離級別:

 READ UNCOMMITTED(未提交讀):

     在READUNCOMMITTED級別,事務中的修改,即使沒有提交,對其他事務也都是可見的。事務可以讀取未提交的數據,這也被稱為臟讀(DirtyRead)。這個級別會導致很多問題,從性能上來說,READUNCOMMITTED不會比其他的級別好太多,但卻缺乏其他級別的很多好處,除非真的有非常必要的理由,在實際應用中一般很少使用。

 READ COMMITTED( 提交讀)

     大多數數據庫系統的默認隔離級別都是READCOMMITTED(但MySQL不是)。READCOMMITTED滿足前面提到的隔離性的簡單定義:一個事務開始時,只能“看見”已經提交的事務所做的修改。換句話說,一個事務從開始直到提交之前,所做的任何修改對其他事務都是不可見的。這個級別有時候也叫做不可重復讀(nonrepeatableread),因為兩次執行同樣的查詢,可能會得到不一樣的結果。

 REPEATABLE READ( 可重復讀)

      REPEATABLEREAD解決了臟讀的問題。該級別保證了在同一個事務中多次讀取同樣記錄的結果是一致的。但是理論上,可重復讀隔離級別還是無法解決另外一個幻讀(PhantomRead)的問題。所謂幻讀,指的是當某個事務在讀取某個范圍內的記錄時,另外一個事務又在該范圍內插入了新的記錄,當之前的事務再次讀取該范圍的記錄時,會產生幻行(PhantomRow)。InnoDB和XtraDB存儲引擎通過多版本並發控制(MVCC,MultiversionConcurrencyControl)解決了幻讀的問題。本章稍后會做進一步的討論。可重復讀是MySQL的默認事務隔離級別。

 

SERIALIZABLE(可串行化)

SERIALIZABLE是最高的隔離級別。它通過強制事務串行執行,避免了前面說的幻讀的問題。簡單來說,SERIALIZABLE會在讀取的每一行數據上都加鎖,所以可能導致大量的超時和鎖爭用的問題。實際應用中也很少用到這個隔離級別,只有在非常需要確保數據的一致性而且可以接受沒有並發的情況下,才考慮采用該級別。

第二部分

 MVCC是如何解決幻讀的呢,來,

      MySQL的大多數事務型存儲引擎實現的都不是簡單的行級鎖。基於提升並發性能的考慮,它們一般都同時實現了多版本並發控制(MVCC)。不僅是MySQL,包括Oracle、PostgreSQL等其他數據庫系統也都實現了MVCC,但各自的實現機制不盡相同,因為MVCC沒有一個統一的實現標准。

      可以認為MVCC是行級鎖的一個變種,但是它在很多情況下避免了加鎖操作,因此開銷更低。雖然實現機制有所不同,但大都實現了非阻塞的讀操作,寫操作也只鎖定必要的行。

      MVCC的實現,是通過保存數據在某個時間點的快照來實現的。也就是說,不管需要執行多長時間,每個事務看到的數據都是一致的。根據事務開始的時間不同,每個事務對同一張表,同一時刻看到的數據可能是不一樣的。如果之前沒有這方面的概念,這句話聽起來就有點迷惑。熟悉了以后會發現,這句話其實還是很容易理解的。

      前面說到不同存儲引擎的MVCC實現是不同的,典型的有樂觀(optimistic)並發控制控制和悲觀(pessimistic)並發控制。

下面我們通過InnoDB的簡化版行為來說明MVCC是如何工作的。

       InnoDB的MVCC,是通過在每行記錄后面保存兩個隱藏的列來實現的。這兩個列,一個保存了行的創建時間,一個保存行的過期時間(或刪除時間)。當然存儲的並不是實際的時間值,而是系統版本號(systemversionnumber)。每開始一個新的事務,系統版本號都會自動遞增。事務開始時刻的系統版本號會作為事務的版本號,用來和查詢到的每行記錄的版本號進行比較。下面看一下在REPEATABLEREAD隔離級別下,MVCC具體是如何操作的。

SELECT    InnoDB會根據以下兩個條件檢查每行記錄:InnoDB只查找版本早於當前事務版本的數據行(也就是,行的系統版本號小於或等於事務的系統版本號),這樣可以確保事務讀取的行,要么是在事務開始前已經存在的,要么是事務自身插入或者修改過的。行的刪除版本要么未定義,要么大於當前事務版本號。這可以確保事務讀取到的行,在事務開始之前未被刪除。只有符合上述兩個條件的記錄,才能返回作為查詢結果。

INSERT    InnoDB為新插入的每一行保存當前系統版本號作為行版本號。

DELETE    InnoDB為刪除的每一行保存當前系統版本號作為行刪除標識。

UPDATE   InnoDB為插入一行新記錄,保存當前系統版本號作為行版本號,同時保存當前系統版本號到原來的行作為行刪除標識。保存這兩個額外系統版本號,使大多數讀操作都可以不用加鎖。這樣設計使得讀數據操作很簡單,性能很好,並且也能保證只會讀取到符合標准的行。不足之處是每行記錄都需要額外的存儲空間,需要做更多的行檢查工作,以及一些額外的維護工作。MVCC只在REPEATABLEREAD和READCOMMITTED兩個隔離級別下工作。其他兩個隔離級別都和MVCC不兼容(4),因為READUNCOMMITTED總是讀取最新的數據行,而不是符合當前事務版本的數據行。而SERIALIZABLE則會對所有讀取的行都加鎖。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM