數據庫——mvcc

 

一、基本概念

mvcc是multi-version concurrency control(多版本併發控制)的英文縮寫,它是現代數據庫解決高併發讀寫場景時,提供高性能的一種併發控制方式,相當於一種數據庫樂觀鎖的實現方式。這裏的多版本是指同一數據會存在多條拷貝,即多個版本,這些版本構成一條版本鏈,而每個事務只能看到其中的某個合理的版本號數據。

二、適用範圍

mvcc適用於數據庫兩種事務隔離級別,即讀已提交和可重複讀,而mvcc與讀未提交和串行化不兼容。另外兩種事務隔離界別,讀未提交,由於可以讀取到其他事務的未提交數據,即最新版本的數據,所以不需要做版本控制;而串行化,直接鎖表或鎖定讀寫的數據行,不存在併發讀寫同一數據的情況,所以也不需要做併發控制。

三、實現方式

在mysql數據的innodb存儲引擎下,每個表都隱含三個隱藏列,其中兩個與mvcc有關(第三個是db_row_id,當表沒有主鍵時,會自動生成一列隱藏主鍵列,大小6字節),即

  • 數據行版本號:db_trx_id,記錄最近更新這條數據或插入數據的事務id,大小6字節
  • 回滾指針:db_roll_ptr,指向該行數據的上一個版本數據的地址,大小7字節。所有舊版本數據在undo log中以鏈表的形式組織在一起。

每當開啓一個事務時,數據庫系統版本號會遞增,而事務會獲取這個版本號作爲這個事務的id。根據mvcc的查詢規則,個人推測系統版本號是隨着新建事務的時間順序,單調遞增的。

1.insert操作

插入數據時,數據行版本號記錄當前事務id,回滾指針是null。

2.update操作

修改數據時,先把舊版本數據複製到undo log中,再修改當前數據,並標記數據行版本號爲當前事務id,回滾指針記錄複製到undo log中的舊版本數據地址

3.delete操作

刪除數據時,修改數據頭部信息中deleted_flag,表示被刪除,當提交時,才刪除。

4.select操作

查詢數據時,會比較當前事務id和數據的數據行版本號,並結合可讀視圖來確定哪些數據可見。

  • 數據行版本號小於當前事務id,說明是當前事務開啓前就提交的數據,因此可以查詢到;數據行版本號等於當前事務id,說明是當前事務插入或修改的數據,因此也可以查詢到。
  • (關於刪除版本號的概念和作用,有待進一步研究)刪除版本號是null,說明是未刪除數據,因此可以查詢到;刪除版本號小於當前事務id,說明是當前事務開啓前就被刪除的數據,因此不會被查詢到;刪除版本號等於當前事務id,說明是當前事務刪除的數據,因此不會被查詢到;刪除版本號大於當前事務id,說明是當前事務開啓後後續事務刪除的數據,相當於時在未來刪除的數據,因此在當前事務中還是可以查詢到的。

四、可讀視圖readview

可讀視圖是在讀已提交或可重複讀隔離級別下,判斷哪些數據可以返回的一個工具,它包含了當前事務執行時,數據庫中所有活躍事務的id。

在讀已提交隔離級別時,一個事務中每次select前,都會生成一份新的可讀視圖。因爲這期間可能有其他事務提交或開啓,所以每次的readview可能不同。而可重複讀隔離級別時,只有在第一次select前才生出可讀視圖,後面的多次select都使用同樣的可讀視圖。

當查詢數據時,會比較數據的行版本號和當前事務可讀視圖。

  • 如果數據行版本號小於可讀視圖中最小的事務id,說明該版本數據在當前事物開啓前就已經提交,因此可以查看。
  • 如果數據行版本號大於可讀視圖中最大的事務id,說明修改該版本數據的事務開啓時間晚於當前事務開啓,即相當於是被未來時間的事務修改的,因此不可以查看。那麼會根據回滾指針,在undo log的版本鏈中,查找上一版本數據,再進行同樣的比較,直到找到符合條件的版本數據。
  • 如果數據行版本號介於可讀視圖中最大的事務id和最小事務id之間,那麼需要比較是否存在與可讀視圖中。如果存在,說明修改數據的事務還沒有提交,那麼不可以查看。如果不存在,說明已經提交,那麼可以查看。

 

更多講解,可參考以下博客

https://juejin.im/post/5c68a4056fb9a049e063e0ab

https://www.jianshu.com/p/f692d4f8a53e

https://draveness.me/database-concurrency-control/

https://zhuanlan.zhihu.com/p/64576887

 

 

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