MVCC并發版本控制
本文大部分來自《MySQL是怎樣運行的》,這里只是簡單總結,用于各位回憶和復習,
版本鏈
對于使用 InnoDB 存盤引擎的表來說,它的聚簇索引記錄中都包含兩個必要的隱藏列(不知道的快去看《MySQL是怎樣運行的》)
-
trx_id :每次一個事務對某條聚簇索引記錄進行改動時,都會把該事務的 事務id 賦值給 trx_id 隱藏列,
-
roll_pointer :每次對某條聚簇索引記錄進行改動時,都會把舊的版本寫入到 undo日志中,然后這個隱藏列就相當于一個指標,可以通過它來找到該記錄修改前的資訊,
假設現在有兩個事務id 分別為 100 、 200 的事務對這條記錄進行 UPDATE 操作,操作流程如下:

每次對記錄進行改動,都會記錄一條undo日志(不懂的可以理解為一個記錄著過去的操作的日志) ,每條 undo日志 也都有一個 roll_pointer 屬性( INSERT 操作對應的 undo日志 沒有該屬性,因為該記錄并沒有更早的版本),可以將這些 undo日志 都連起來,串成一個鏈表,所以現在的情況就像下圖一樣:

對該記錄每次更新后,都會將舊值放到一條 undo日志 中,就算是該記錄的一個舊版本,隨著更新次數的增多, 所有的版本都會被 roll_pointer 屬性連接成一個鏈表,我們把這個鏈表稱之為 版本鏈 ,版本鏈的頭節點就是當 前記錄最新的值,另外,每個版本中還包含生成該版本時對應的 事務id ,這個資訊很重要,我們稍后就會用到,
ReadView
我們來引出一下readview是什么東西:
對于使用 READ UNCOMMITTED 隔離級別的事務來說,由于可以讀到未提交事務修改過的記錄,所以直接讀取記錄的最新版本就好了
對于使用 SERIALIZABLE 隔離級別的事務來說,則是使用加鎖的方式來問記錄
但是!!!對于使用 READ COMMITTED 和 REPEATABLE READ 隔離級別的事務來說
都必須保證讀到已經提交了的事務修改過的記錄,也就是說假如另一個事務已經修改了記錄但是尚未提交, 是不能直接讀取最新版本的記錄的,核心問題就是:需要判斷一下版本鏈中的哪個版本是當前事務可見的,為此,設計 InnoDB 的大叔提出了一個 ReadView 的概念,這個 ReadView 中主要包含4個比較重要的內容:
-
m_ids :表示在生成 ReadView 時當前系統中活躍的讀寫事務的事務id 串列,
-
min_trx_id :表示在生成 ReadView 時當前系統中活躍的讀寫事務中最小的事務id ,也就是 m_ids 中的最小值,
-
max_trx_id :表示生成 ReadView 時系統中應該分配給下一個事務的 id 值,
-
小貼士: 注意max_trx_id并不是m_ids中的最大值,事務id是遞增分配的,比方說現在有id為1,2,3這三 個事務,之后id為3的事務提交了,那么一個新的讀事務在生成ReadView時,m_ids就包括1和2,mi n_trx_id的值就是1,max_trx_id的值就是4,
-
-
creator_trx_id :表示生成該 ReadView 的事務的事務id ,
-
小貼士: 我們前邊說過,只有在對表中的記錄做改動時(執行INSERT、DELETE、UPDATE這些陳述句時)才會 為事務分配事務id,否則在一個只讀事務中的事務id值都默認為0,
-
有了 ReadView ,這樣在訪問某條記錄時,只需要按照下邊4個步驟判斷記錄的某個版本是否可見:注意,與被訪問版本對比的東西都是指(當前最新的ReadView)
-
如果(被訪問版本的) trx_id = creator_trx_id ,意味著當前事務在訪問它自己修改過的記錄,所以該版本可以被當前事務訪問,
-
如果(被訪問版本的) trx_id < min_trx_id ,表明生成該版本的事務在當前事務生成 ReadView 前已經提交,所以該版本可以被當前事務訪問,
-
如果(被訪問版本的) trx_id > max_trx_id ,表明生成該版本的事務在當前事務生 成 ReadView 后才開啟,所以該版本不可以被當前事務訪問,
-
如果(被訪問版本的)min_trx_id < trx_id < max_trx_id ,那就需要判斷一下 trx_id 屬性值是不是在 m_ids 活躍事務串列中,
-
如果在,說明創建 ReadView 時生成該版本的事務還是活躍的,還沒提交,該版本不可以被訪問,
-
如果不在,說明創建 ReadView 時生成該版本的事務已經被提交,該版本可以被訪問,
-
ReadView生成時機
讀已提交 和 可重復讀 隔離級別最大的區別就是它們生成ReadView的時機不同:
-
READ COMMITTED —— 每次讀取資料前都生成一個ReadView
-
每次select操作都生成一個ReadView,所以每一次查詢都在用一個最新生成的ReadView進行上述4步走,所以查出來的應該是最新提交的事務中的最后一個操作(因為一個事務可能有多個增改操作)
-
-
REPEATABLE READ —— 在第一次讀取資料時生成一個ReadView
-
意味著你在第一次執行select陳述句之后,不管增刪改了多少次,永遠拿第一次select生成的ReadView來進行剛剛說的4個步驟判斷,所以一直查詢的是第一次select陳述句所查出來的東西,
-
具體例子這里不過多贅述,還是自行看書,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/555632.html
標籤:其他
下一篇:返回列表
