讀了 @SnailMann大佬【MySQL筆記】正確的理解MySQL的MVCC及實作原理 收益頗豐,非常感謝!
但對其中如何判斷事務是否可見性還是不太理解,于是作了本文,在原博客基礎上,舉例畫圖論證、理解了Read View的可見性判斷,
參考 @SnailMann大佬【MySQL筆記】正確的理解MySQL的MVCC及實作原理 的欄位說明,
隱式欄位
每行記錄除了我們自定義的欄位外,還有資料庫隱式定義的 DB_TRX_ID, DB_ROLL_PTR, DB_ROW_ID 等欄位
DB_TRX_ID
6 byte,最近修改(修改/插入)事務 ID:記錄創建這條記錄/最后一次修改該記錄的事務 IDDB_ROLL_PTR
7 byte,回滾指標,指向這條記錄的上一個版本(存盤于 rollback segment 里)DB_ROW_ID
6 byte,隱含的自增 ID(隱藏主鍵),如果資料表沒有主鍵,InnoDB 會自動以DB_ROW_ID產生一個聚簇索引
Read View 的三個全域屬性
trx_list(名稱我隨意取的):一個數值串列,用于維護Read View生成時刻系統 正活躍的事務 ID 串列
up_limit_id:是trx_list串列中事務 ID 最小的 ID
low_limit_id:Read View生成時刻系統尚未分配的下一個事務 ID ,也就是 目前已出現過的事務 ID 的最大值 + 1
為什么是low_limit? 因為它也是系統此刻可分配的事務 ID 的最小值
可見性判斷邏輯
-
DB_TRX_ID < up_limit_id, 當前行事務id比活躍的最小事務id還小時,說明了兩件事,當前行事務對該記錄的修改已經提交,因為當前事務id比活躍的最小事務id還小,不在活躍的事務之中,也就意味著該事務已經提交或回滾,這時因為已經成功修改,那么應該就是提交成功了,
也就是在生成Read View之前,事務已經提交, -
接下來判斷
DB_TRX_ID >= low_limit_id, 修改該行的事務id大于了Read View里系統待分配的下一個事務id,說明修改該行的事務是生成該Read View之后出現的事務,因為Read View系統待分配的下一個事務id被用了,才會出現比該事務id大的事務,這時,也應該是不可見的,一個事務怎么可以看到后面新來事務做的修改了, -
判斷
DB_TRX_ID是否在活躍事務之中,trx_list.contains (DB_TRX_ID),如果在活躍事務之中,說明該修改是其他事務未提交的修改,應該是不可見的,如果可見就是臟讀了,如果不在活躍事務之中,說明在生成Read View之前,該事務的修改就已提交,與第一個判斷邏輯類似,事務2是可以查到這條記錄的,
針對上面三種情況,下面舉例說明:
原記錄:amount = 100
| 事務1 | 事務2 | 事務3 | 事務4 |
|---|---|---|---|
| 開啟事務 | 開啟事務 | 開啟事務 | |
update amount = 200 |
|||
update amount = 300 |
提交事務 | ||
①select amount; 開始快照讀,生成Read View |
|||
| 提交事務 | 開啟事務 | ||
②select amount; |
|||
update amount = 400; |
|||
| 提交事務 | |||
③select amount; |
請問三次select amount; 快照讀到的值分別是多少,為什么?
畫一張圖,把undo表里存的記錄版本鏈及當前記錄畫出來,

①
1>如圖,當前行 DB_TRX_ID(1) == up_limit_id(1),說明本次修改該記錄的事務正在進行中,也就是事務1還未結束,事務2就應該對事務1這次修改不可見,可見就是臟讀了,
2>當前記錄不可見,再根據回滾指標追蹤到上個版本記錄,如圖undo日志內 金額為200的行,此時再通過Read View進行可見性判斷,
第一種情況:當前行 DB_TRX_ID(3) > up_limit_id(1),不確定;
第二種情況:DB_TRX_ID(3) < low_limit_id(4),也不確定;
第三種情況:DB_TRX_ID(3)不在trx_list中,不是活躍的事務,說明事務3在事務2生成Read View之前就已經提交,那么是可見的,
所以讀取的金額為200,
②
事務1提交事務,不過undo表與當前行資料無變化,對事務1的Read View的資料也不會變化,因為RR模式下,Read View 只會在第一次快照讀時生成,后面幾次快照讀不會生成新的 Read View,也不會改動之前Read View的值,
當前行資料與Read View 都無變化,那么可見性判斷也同①一致,讀取到的金額為200,
③
第一種情況:當前行 DB_TRX_ID(4) > up_limit_id(1),不確定;
第二種情況:DB_TRX_ID(4) > low_limit_id(1),說明當前行是被生成Read View之后出現的事務修改的,這種未來的資料肯定是不可見的,
再接著追溯,就與①中追溯的程序相差不大了,最終讀取的金額也是為200,
總結
這里舉例論證了可見性判斷的合理性,總結來說,可見性的三個判斷約束了一件事,只有在本事務生成Read View之前就已經提交的事務的修改才可以被看見,其他的無論是正在進行的事務的修改還是之后再提交的事務的修改都不可見,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/499116.html
標籤:MySQL
