數據庫MVCC總結

爲何須要MVCC

當多個數據庫事務同時運行,其修改數據產生的中間狀態對於其餘事務的可見性是數據庫隔離級別來限制的,而這個可見性的約束有四種sql

  • 讀未提交
  • 讀已提交
  • 可重複讀
  • 串行化

其中讀未提交最弱,多個事務共享一份數據就行了,而串行化最強,讀取加讀鎖,寫數據加寫鎖,而讀已提交和可重複讀都須要有「不讀取未提交的數據」和「只讀取建立事務以前的數據」這樣的需求,而實現這樣的需求,天然而然的想到要引入「快照」的概念,也就是對數據庫的每一行,併發修改的時候生成快照,在MySQL,快照的實現藉助的是MVCC,即多版本併發控制,下面將主要圍繞快照如何組織,以及如何使用快照兩個部分對MVCC進行描述。數據庫

快照如何組織?

MySQL的快照依賴的是版本鏈,也就是UndoLog,UndoLog在每次修改數據的時候,保留數據最初始的版本,同時記錄最新版,既然是鏈,就有指針,這個指針在每行數據的隱藏字段當中,同時,每次修改的快照天然須要記錄是誰修改的,這個誰就是事務,事務有本身的惟一,自增的事務Id,惟一是標識事務的必要條件,而自增,則給了事務Id順序性的含義,順序的ID對於以後使用快照的階段很是重要,固然事務Id和undo指針同樣都在每行數據的隱藏字段當中。markdown

image.png 其中trx_id就是事務Id,roll_p就是指針併發

若是有一條記錄爲A,通過了以下的操做oop

事務2 事務3
begin;
將A修改成B begin;
將B修改成C(時刻1)
commit;
commit;

那麼在時刻1的版本鏈以下所示:spa

image.png

如今版本鏈已經有了,可是如何使用,只靠一個版本鏈是缺少足夠的信息來實現讀已提交和可重複讀的,咱們還缺少在事務建立的一些額外的信息,就比如,讀已提交須要知道什麼是已提交,進一步,哪些事務是已提交的,等等,這些信息構成了使用MVCC的運行時上下文,下面咱們總結下MVCC使用的上下文信息。線程

快照如何使用?

建立快照的時候也須要記錄一些建立時刻的基本信息,好比建立事務的時刻,有哪些事務正在運行,這些數據方便界定哪些事務是已經提交了的,我能夠讀了,也須要當前事務的事務Id,也須要在建立快照的那一剎那,標識對於當前的事務而言,哪些事務對於當前的事務是不可見的將來。對於這些數據,以下圖所示:指針

image.png

其中m_ids表示建立事務的那一刻,當前運行中的事務,creator_trx_id表示建立者事務,min_trx_idm_ids的最小值,小於min_trx_id的事務Id對當前事務而言是妥妥的已提交,而max_trx_id是當前事務Id的下一個Id。code

快照如何工做,主要依賴以上描述的信息搭配undoLog鏈:orm

  • 若是訪問undolog版本的trx_id屬性值creator_trx_id相同,則是本身的記錄,可見
  • 若是trx_id小於min_trx_id則表明該記錄已經提交,可見
  • 若是trx_id大於等於max_trx_id則是建立該視圖以後的事務,不可見
  • 若是trx_id處於min_trx_idmax_trx_id之間,則須要判斷此時此刻trx_id是否在m_ids之間,若是依然在,則不可見。

讀已提交和可重複讀的區別

上面描述的基本信息包含在一次讀視圖中(ReadView)

  • 對於讀提交,是每次讀操做都會建立新的視圖,對於這種狀況一個事務中讀視圖中的數據是不斷變化的,所以每次能讀取到最新的提交
  • 對於可重複讀,是每次事務讀的時候建立一個視圖,而且一直沿用。

版本鏈什麼時候清除

  • 後臺運行Purge線程在什麼時候的時候進行刪除

注意事項

因爲MVCC版本鏈的機制,可見爲了支持MVCC,更新的數據能夠和老數據同時留存,刪除的數據也不會當即刪除,而是打上刪除標記,所以必定要注意長事務對於MySQL自己的影響

在開發過程當中,能夠設置set autocommit=1

查詢長事務能夠經過以下的語句來查看:

select
    * 
from information_schema.innodb_trx
where 
TIME_TO_SEC(timediff(now(),trx_started))>60
複製代碼

參考資料

掘金小冊 極客時間

相關文章
相關標籤/搜索