MVCC——多版本併發控制

概念

Multi Version Concurrency Control, 用於數據庫的併發訪問控制

MVCC在mysql innoDB中的實現主要是爲了提高數據庫併發性能, 用更好的方式去處理讀-寫衝突, 實現讀寫衝突不加鎖, 非阻塞併發讀寫

每一次的數據修改都會將歷史記錄保存在Undo log裏, 讀數據採用快照讀的方式, 這樣就不會有阻塞了

什麼是當前讀和快照讀

當前讀

共享鎖、排他鎖 都是保證其他事務不能併發修改當前記錄, 所以讀取的肯定是最新紀錄

快照讀

簡單理解就是 不加鎖的select、快照讀的前提是基於多版本控制, 快照讀讀取的不一定是最新數據, 有可能是某個版本的數據

MVCC能解決什麼問題

數據庫併發場景有三種,分別爲:

  • 讀-讀:不存在任何問題,也不需要併發控制
  • 讀-寫:有線程安全問題,可能會造成事務隔離性問題,可能遇到髒讀,幻讀,不可重複讀
  • 寫-寫:有線程安全問題,可能會存在更新丟失問題,比如第一類更新丟失,第二類更新丟失

MVCC 帶來的好處是?
多版本併發控制(MVCC)是一種用來解決讀-寫衝突無鎖併發控制,也就是爲事務分配單向增長的時間戳,爲每個修改保存一個版本,版本與事務時間戳關聯,讀操作只讀該事務開始前的數據庫的快照。 所以 MVCC 可以爲數據庫解決以下問題

  • 在併發讀寫數據庫時,可以做到在讀操作時不用阻塞寫操作,寫操作也不用阻塞讀操作,提高了數據庫併發讀寫的性能
  • 同時還可以解決髒讀,幻讀,不可重複讀等事務隔離問題,但不能解決更新丟失問題

小結一下咯
簡而言之,MVCC 就是因爲大佬們,不滿意只讓數據庫採用悲觀鎖這樣性能不佳的形式去解決讀-寫衝突問題,而提出的解決方案,所以在數據庫中,因爲有了 MVCC,所以我們可以形成兩個組合:

  • MVCC + 悲觀鎖
    MVCC解決讀寫衝突,悲觀鎖解決寫寫衝突
  • MVCC + 樂觀鎖
    MVCC 解決讀寫衝突,樂觀鎖解決寫寫衝突

MVCC 的實現原理

爲了解決**讀寫衝突,它的實現原理主要是依賴記錄中的** 3個隱式字段undo日誌 ,Read View 來實現的

隱式字段

1、DB_TRX_ID

6 byte, 最近修改(修改和插入)的事務ID: 創建這條記錄/修改這條記錄的最後一次事務ID

2、DB*_ROLL_PTR*

7 byte, 回滾指針, 指向這條記錄的上一個版本 (指向的是undo log)

3、DB_ROW_ID

6 byte, 隱含的自增 ID(隱藏主鍵),如果數據表沒有主鍵,InnoDB 會自動以DB_ROW_ID          產生一個聚簇索引
實際還有一個刪除 flag 隱藏字段, 既記錄被更新或刪除並不代表真的刪除,而是刪除 flag 變了

undo log

undo log 主要分爲兩種:

1、insert undo log
      代表事務在 insert 新記錄時產生的 undo log, 只在事務回滾時需要,並且在事務提交後可以被立即丟棄
2、update undo log
      事務在進行 update 或 delete 時產生的 undo log ; 不僅在事務回滾時需要,在快照讀時也需要;所以不能隨便刪除,只有在快速讀或事務回滾不涉及該日誌時,對應的日誌纔會被 purge線程統一清除

	purge
*   從前面的分析可以看出,爲了實現 InnoDB 的 MVCC 機制,更新或者刪除操作都只是設置一下老記錄的 deleted\_bit ,並不真正將過時的記錄刪除。
*   爲了節省磁盤空間,InnoDB 有專門的 purge 線程來清理 deleted\_bit 爲 true 的記錄。爲了不影響 MVCC 的正常工作,purge 線程自己也維護了一個read view(這個 read view 相當於系統中最老活躍事務的 read view );如果某個記錄的 deleted\_bit 爲 true ,並且 DB\_TRX\_ID 相對於 purge 線程的 read view 可見,那麼這條記錄一定是可以被安全清除的。

Read View 讀視圖

說白了 Read View 就是事務進行 快照讀 操作的時候生產的 讀視圖 (Read View),在該事務執行的快照讀的那一刻,會生成數據庫系統當前的一個快照,記錄並維護系統當前活躍事務的 ID (當每個事務開啓時,都會被分配一個 ID , 這個 ID 是遞增的,所以最新的事務,ID 值越大)

Read View 遵循一個可見性算法,主要是將 要被修改的數據 的最新記錄中的 DB_TRX_ID(即當前事務 ID )取出來,與系統當前其他活躍事務的 ID 去對比(由 Read View 維護),如果 DB_TRX_ID 跟 Read View 的屬性做了某些比較,不符合可見性,那就通過 DB_ROLL_PTR 回滾指針去取出 Undo Log 中的 DB_TRX_ID 再比較,即遍歷鏈表的 DB_TRX_ID(從鏈首到鏈尾,即從最近的一次修改查起),直到找到滿足特定條件的 DB_TRX_ID , 那麼這個 DB_TRX_ID 所在的舊記錄就是當前事務能看見的最新老版本

MVCC 相關問題

RC , RR 級別下的 InnoDB 快照讀有什麼不同?

RC: 讀已提交 RR: 可重複讀

正是** Read View** 生成時機的不同,從而造成 RC , RR 級別下快照讀的結果的不同

  • 在 RR 級別下的某個事務的對某條記錄的第一次快照讀會創建一個快照及 Read View, 將當前系統活躍的其他事務記錄起來,此後在調用快照讀的時候,還是使用的是同一個 Read View,所以只要當前事務在其他事務提交更新之前使用過快照讀,那麼之後的快照讀使用的都是同一個 Read View,所以對之後的修改不可見;
  • 即 RR 級別下,快照讀生成 Read View 時,Read View 會記錄此時所有其他活動事務的快照,這些事務的修改對於當前事務都是不可見的。而早於Read View創建的事務所做的修改均是可見
  • 而在 RC 級別下的,事務中,每次快照讀都會新生成一個快照和 Read View , 這就是我們在 RC 級別下的事務中可以看到別的事務提交的更新的原因
  • 總之在 RC 隔離級別下,是每個快照讀都會生成並獲取最新的 Read View;而在 RR 隔離級別下,則是同一個事務中的第一個快照讀纔會創建 Read View, 之後的快照讀獲取的都是同一個 Read View。

參考資料:

https://blog.csdn.net/bbj12345678/article/details/120780051

【【MySql】理解Read View(事務 undolog MVCC)】 https://www.bilibili.com/video/BV1A24y187ss/?share_source=copy_web&vd_source=95687cb0a9238b1e583346db070aefae

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