MySQL事務實現原理

dead_lee發表於2021-09-09

MySQL事務隔離級別的實現原理

知識儲備

  • 只有InnoDB支援事務,所以這裡說的事務隔離級別是指InnoDB下的事務隔離級別

  • 隔離級別

    • 讀未提交:一個事務可以讀取到另一個事務未提交的修改。這會帶來髒讀,幻讀,不可重複讀問題

    • 讀已提交:一個事務只能讀取另一個事務已經提交的修改。其避免了髒讀,仍然存在不可以重複讀和幻讀問題

    • 可重複讀:同一個事務中多次讀取相同的資料返回的結果是一樣的。其避免了髒讀和不可重複讀問題,但是幻讀依然存在

    • 序列化:事務序列之行。避免了以上所有問題

以上是SQL-92標準中定義的四種隔離級別。在MySQL中,預設的隔離級別是REPEATABLE-READ(可重複讀),並且解決了幻讀問題。

不可重複讀重點在於Update和delete,而幻讀的重點在於insert

MVCC

  • MVCC的全稱是多版本併發控制。MVCC使得InnoDB的事務隔離級別下執行一致性讀操作有了保證。簡單說就是為了查詢一些正在被另一個事務更新的行,並且可以看到它們被更新之前的值。這是一個用來增強併發性的強大技術,可以使得查詢不用等待另一個事務釋放鎖。

  • MVCC會給每一行增加三個欄位。分別是DB-TRX-ID DB-ROLL-PTR,DB-ROW-ID

  • 增刪查改
    在InnoDB中,給每行增加兩個隱藏欄位來實現MVCC,一個用來記錄資料行的建立時間,另一個用來記錄行的過期時間,在實際操作中,儲存的並不是時間,而是事務版本號,每開啟一個新事務,事務的版本號就會遞增。所以增刪改查中對版本號的作用如下:

    • 將當前事務版本號儲存至行的刪除版本號

    • 新插入一行,並以當前事務版本號作為新行的建立版本號,同時將原記錄行的刪除版本號設定為當前事務版本號

    • 將當前事務的版本號儲存至行的建立版本號

    • 讀取建立版本小於或等於當前事務版本號,並且刪除版本為空或大於當前事務版本的記錄。這樣可以保證在讀取之前記錄都是存在的

    • select:

    • insert:

    • update

    • delete

  • 快照讀和當前讀

    • 快照讀:讀取的是快照版本,也就是歷史版本

    • 當前讀:讀取的是最新版版

    • 普通的select就是快照讀,而update,delete,insert,select...LOCK In SHARE MODE,SELECT...for update就是當前讀

一致性非鎖定讀和鎖定讀

鎖定讀
  • 在一個事務中,標準的SELECT語句是不會加鎖,但是有兩種情況例外。SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE。

    • SELECT ... LOCK IN SHARE MODE:給記錄假設共享鎖,這樣其他事務職能讀不能修改,直到當前事務提交

    • SELECT ... FOR UPDATE:給索引記錄加鎖,這種情況跟UPDATE的加鎖情況是一樣的

一致性非鎖定讀
  • consistent read(一致性讀),InnoDB用多版本來提供查詢資料庫在某個時間點的快照。如果隔離級別是REPEATABLE READ,那麼在同一個事務中的所有一致性讀都讀的是事務中第一個的讀讀到的快照;如果是READ COMMITTED,那麼一個事務中的每一個一致性讀都會讀到它自己重新整理的快照版本。Consistent read(一致性讀)是READ COMMITTED和REPEATABLE READ隔離級別下普通SELECT語句預設的模式。一致性讀不會給它鎖訪問的表加任何形式的鎖,因此其他事務可以同時併發的修改它們

  • Record Locks(記錄鎖):在索引記錄上加鎖

  • Gap Locks(間隙鎖):在索引記錄之間加鎖,或者在第一個索引記錄之前加鎖,或者在最後一個索引記錄之後加鎖

  • Next-Key Locks:在索引記錄上加鎖,並且在索引記錄之前的間隙加鎖。相當於Record Locks與Gap Locks的一個結合

假如一個索引包含以下幾個值:10,11,13,20.那麼這個索引的next-key鎖將會覆蓋以下區間:
(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)

理論分析

  • 在預設的隔離級別中,普通的SELECT用的是一致性讀不加鎖。而對於鎖定讀,UPDATE和DELETE,則需要加鎖,至於加什麼鎖是有不同情況的。如果對一個唯一索引使用了唯一的檢索條件,那麼只需要鎖定相應的索引記錄就好;如果是沒有使用唯一索引作為檢索條件,或者用到了索引範圍掃描,那麼將會使用間隙鎖或者next-key鎖來以此阻塞其他會話向這個範圍內的間隙插入資料

    • 利用MVCC實現一致性非鎖定讀,保證在同一個事務中多次讀取相同的資料返回的結果是一樣的,解決了不可重複讀問題

    • 利用Gap Locks和Next-key可以阻止其他事務在鎖定區間內插入資料,解決了幻讀問題

綜上所述,MySQL的預設隔離級別的實現依賴於MVCC和鎖,準確點說就是一致性讀和鎖

例項分析

客戶端A

  • 客戶端A開始一個事務,並以主鍵唯一索引作為檢索條件進行更新

圖片描述

客戶端B

  • 客戶端B開始一個事務,由於客戶端A已經開始了事務並以主鍵索引作為檢索條件,所以會造成該索引被鎖定。其他索引以及其他範圍則不會被鎖定可以正常操作

圖片描述

客戶端A

  • 當客戶端A重新開始一個事務並沒有使用唯一索引作為檢索條件

圖片描述

客戶端B

  • 客戶端B開始一個事務,由於客戶端A的事務操作,那麼mysql會使用next-key和間隙鎖以此阻塞其他會話對錶的操作

圖片描述

原文出處:https://www.cnblogs.com/develop-SZT/p/10339138.html 

作者:  

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4686/viewspace-2820862/,如需轉載,請註明出處,否則將追究法律責任。

相關文章