MVCC總結

下面內容是參考文章末尾博客做的一點總結,博客中講解的很好,但是對其中一些說法不是很贊同,所以下面只整理認同的部分。

多版本控制

指的是一種提高併發的技術。最早的數據庫系統,只有讀讀之間可以併發,讀寫,寫讀,寫寫都要阻塞。引入多版本之後,只有寫寫之間相互阻塞,其他三種操作都可以並行,這樣大幅度提高了InnoDB的併發度。

ReadView

事務快照是用來存儲數據庫的事務運行情況。一個事務快照的創建過程可以概括爲:

  1. 查看當前所有的未提交併活躍的事務,存儲在數組中
  2. 選取未提交併活躍的事務中最小的XID,記錄在快照的xmin中
  3. 選取所有已提交事務中最大的XID,加1後記錄在xmax中

這裏暫時不知道ReadView中是否包含當前事務,如果包含當前事務,那麼根據下面的可見性算法,事務對記錄進行變更後在事務內不能可見。

RR隔離級別下,ReadView是在事務中第一次select的讀操作時創建。RC隔離級別下,在事務中每一次select都會創建ReadView。

Undo log

當對記錄進行變更時就會產生Undo記錄,Undo記錄分爲兩個種Insert Undo log和Update Undo log。Insert Undo log記錄事務的insert操作,只用於事務回滾,事務提交後就可以刪除。Update Undo log記錄事務的update和delete操作,不僅事務回滾需要,在讀取時也需要,所以不能隨便刪除,只有當ReadView中沒有關聯到當前Undo log時,纔可以被刪除。

DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID

這三個字段是InnoDB添加的隱藏字段,DB_TRX_ID表示最後一次變更該條記錄的事務,DB_ROLL_PTR表示回滾指針指向該記錄上一個版本,DB_ROW_ID表示默認的聚簇索引(這裏不考慮)

Undo鏈

每次記錄更新時,都會保存上一個版本,Undo鏈就是維持這些版本關係的模型。例如,當更新一條記錄時,會對這個記錄加鎖,將改行記錄修添加到Undo log,將Undo log位置記錄到DB_ROLL_PTR 最後修改記錄值,將事務id記錄到DB_TRX_ID。每次更新記錄就保存一個Undo log,這樣就構成了可以找到舊版本的Undo鏈。

可見性算法

創建ReadView, ReadView中最小的事務id爲up_limit_id,最大的事務id爲low_limit_id

  1. 記錄的DB_TRX_ID小於up_limit_id,記錄由之前已經提交的事務變更,記錄對當前事務可見
  2. 記錄的DB_TRX_ID大於low_limit_id,記錄由新開啓的事務變更,當前事務不能確定新事務是否提交,所以記錄對當前事務不可見。
  3. 記錄的DB_TRX_ID介於up_limit_id和low_limit_id之間,遍歷ReadView如果不包含DB_TRX_ID則說明變更該條記錄的事務已提交,記錄對當前事務可見。否則,記錄不可見,查找Undo鏈中可見的記錄。

MVCC如何實現讀已提交和可重複讀

  1. RC隔離級別下每次select時創建一個ReadView(假設不包含當前事務),根據可見性算法,只有DB_TRX_ID小於low_limit_id並且DB_TRX_ID不在ReadView中時,也就是DB_TRX_ID對應的事務已經提交。所以記錄一定是由已提交事務變更。
  2. RR隔離級別下,因爲ReadView不變,根據可見性算法計算得到的結果也不變,所以每次select得到的記錄都應該是一樣的。

MVCC和幻讀

幻讀是指用同樣的條件查詢或更新,前後的影響的記錄數量不同

  1. 在RR隔離級別下,根據上面MVCC實現可重複讀,可以發現對於select來說,MVCC已經保證不會出現幻讀
  2. 如果對記錄進行更新則需要對記錄加鎖,InnoDB的加鎖策略(gap lock)會保證不產生幻讀

 

參考:

https://segmentfault.com/a/1190000012650596?utm_source=tag-newest

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章