摘要在當今高度并發的數據庫環境中,有效的并發控制是至關重要的。MVCC是MySQL中被廣泛采用的并發控制機制,它通過版本管理來實現事務的隔離性,允許讀寫操作同時進行,提高數據庫的并發性能和響應能力。Tzb28資訊網——每日最新資訊28at.com
本文將深入解析MVCC機制的原理,幫助讀者更好地理解和應用這一關鍵技術。Tzb28資訊網——每日最新資訊28at.com
MVCC 介紹MVCC,全稱 Multi-Version Concurrency Control,即多版本并發控制Tzb28資訊網——每日最新資訊28at.com
MVCC的目的主要是為了提高數據庫并發性能,用更好的方式去處理讀-寫沖突,做到即使有讀寫沖突時,也能做到不加鎖。Tzb28資訊網——每日最新資訊28at.com
這里的多版本指的是數據庫中同時存在多個版本的數據,并不是整個數據庫的多個版本,而是某一條記錄的多個版本同時存在。Tzb28資訊網——每日最新資訊28at.com
并發控制的挑戰Tzb28資訊網——每日最新資訊28at.com
在數據庫系統中,同時執行的事務可能涉及相同的數據,因此需要一種機制來保證數據的一致性,傳統的鎖機制可以實現并發控制,但會導致阻塞和死鎖等問題。Tzb28資訊網——每日最新資訊28at.com
MVCC的優點Tzb28資訊網——每日最新資訊28at.com
MVCC機制具有以下優點:Tzb28資訊網——每日最新資訊28at.com
提高并發性能:讀操作不會阻塞寫操作,寫操作也不會阻塞讀操作,有效地提高數據庫的并發性能。Tzb28資訊網——每日最新資訊28at.com
降低死鎖風險:由于無需使用顯式鎖來進行并發控制,MVCC可以降低死鎖的風險。Tzb28資訊網——每日最新資訊28at.com
當前讀和快照讀
在講解MVCC原理之前,我們先來了解一下,當前讀和快照讀。Tzb28資訊網——每日最新資訊28at.com
當前讀Tzb28資訊網——每日最新資訊28at.com
在MySQL中,當前讀是一種讀取數據的操作方式,它可以直接讀取最新的數據版本,讀取時還要保證其他并發事務不能修改當前記錄,會對讀取的記錄進行加鎖。MySQL提供了兩種實現當前讀的機制:Tzb28資訊網——每日最新資訊28at.com
默認隔離級別下(可重復讀),MySQL使用一致性讀來實現當前讀。Tzb28資訊網——每日最新資訊28at.com
在事務開始時,MySQL會創建一個一致性視圖(Consistent View),該視圖反映了事務開始時刻數據庫的快照。Tzb28資訊網——每日最新資訊28at.com
在事務執行期間,無論其他事務對數據進行了何種修改,事務始終使用一致性視圖來讀取數據。Tzb28資訊網——每日最新資訊28at.com
這樣可以保證在同一個事務內多次查詢返回的結果是一致的,從而實現了當前讀。Tzb28資訊網——每日最新資訊28at.com
- 鎖定讀(Locking Read):
- 鎖定讀是一種特殊情況下的當前讀方式,在某些場景下使用。
- 當使用鎖定讀時,MySQL會在執行讀取操作前獲取共享鎖或排他鎖,以確保數據的一致性。
- 共享鎖(Shared Lock)允許多個事務同時讀取同一數據,而排他鎖(Exclusive Lock)則阻止其他事務讀取或寫入該數據。
- 鎖定讀適用于需要嚴格控制并發訪問的場景,但由于加鎖帶來的性能開銷較大,建議僅在必要時使用。
下面列舉的這些語法都是當前讀:Tzb28資訊網——每日最新資訊28at.com
語法Tzb28資訊網——每日最新資訊28at.com |
SELECT ... LOCK IN SHARE MODETzb28資訊網——每日最新資訊28at.com |
SELECT ... FOR UPDATETzb28資訊網——每日最新資訊28at.com |
UPDATETzb28資訊網——每日最新資訊28at.com |
DELETETzb28資訊網——每日最新資訊28at.com |
INSERTTzb28資訊網——每日最新資訊28at.com |
當前讀實際上是一種加鎖的操作,是悲觀鎖的實現。Tzb28資訊網——每日最新資訊28at.com
快照讀Tzb28資訊網——每日最新資訊28at.com
快照讀是在讀取數據時讀取一個一致性視圖中的數據,MySQL使用 MVCC 機制來支持快照讀。Tzb28資訊網——每日最新資訊28at.com
具體而言,每個事務在開始時會創建一個一致性視圖(Consistent View),該視圖反映了事務開始時刻數據庫的快照。這個一致性視圖會記錄當前事務開始時已經提交的數據版本。Tzb28資訊網——每日最新資訊28at.com
當執行查詢操作時,MySQL會根據事務的一致性視圖來決定可見的數據版本。只有那些在事務開始之前已經提交的數據版本才是可見的,未提交的數據或在事務開始后修改的數據則對當前事務不可見。Tzb28資訊網——每日最新資訊28at.com
像不加鎖的 select 操作就是快照讀,即不加鎖的非阻塞讀。Tzb28資訊網——每日最新資訊28at.com
快照讀可能讀到的并不一定是數據的最新版本,而有可能是之前的歷史版本。Tzb28資訊網——每日最新資訊28at.com
注意:快照讀的前提是隔離級別不是串行級別,在串行級別下,事務之間完全串行執行,快照讀會退化為當前讀Tzb28資訊網——每日最新資訊28at.com
MVCC主要就是為了實現讀-寫沖突不加鎖,而這個讀指的就是快照讀,是樂觀鎖的實現。Tzb28資訊網——每日最新資訊28at.com
MVCC 原理解析
隱式字段
MySQL中的行數據,除了我們肉眼能看到的字段之外,其實還包含了一些隱藏字段,它們在內部使用,默認情況下不會顯示給用戶。Tzb28資訊網——每日最新資訊28at.com
字段Tzb28資訊網——每日最新資訊28at.com | 含義Tzb28資訊網——每日最新資訊28at.com |
DB_ROW_IDTzb28資訊網——每日最新資訊28at.com | 隱含的自增ID(隱藏主鍵),用于唯一標識表中的每一行數據,如果數據表沒有主鍵,InnoDB會自動以DB_ROW_ID產生一個聚簇索引。Tzb28資訊網——每日最新資訊28at.com |
DB_TRX_IDTzb28資訊網——每日最新資訊28at.com | 該字段存儲了當前行數據所屬的事務ID。每個事務在數據庫中都有一個唯一的事務ID。通過 DB_TRX_ID 字段,可以追蹤行數據和事務的所屬關系。Tzb28資訊網——每日最新資訊28at.com |
DB_ROLL_PTRTzb28資訊網——每日最新資訊28at.com | 該字段存儲了回滾指針(Roll Pointer),它指向用于回滾事務的Undo日志記錄。Tzb28資訊網——每日最新資訊28at.com |
Undo Log
上文提到了 Undo 日志,這個 Undo 日志是 MVCC 能夠得以實現的核心所在。Tzb28資訊網——每日最新資訊28at.com
Undo日志(Undo Log)是MySQL中的一種重要的事務日志,Undo日志的作用主要有兩個方面:Tzb28資訊網——每日最新資訊28at.com
- 事務回滾:當事務需要回滾時,MySQL可以通過Undo日志中的舊值將數據還原到事務開始之前的狀態,保證了事務回滾的一致性。
- MVCC實現:MVCC 是InnoDB存儲引擎的核心特性之一。通過使用Undo日志,MySQL可以為每個事務提供獨立的事務視圖,使得事務讀取數據時能看到一致且符合隔離級別要求的數據版本。
在InnoDB存儲引擎中,Undo日志分為兩種:插入(insert)Undo日志 和 更新(update)Undo日志Tzb28資訊網——每日最新資訊28at.com
- insert undo log:插入Undo日志是指在插入操作中生成的Undo日志。由于插入操作的記錄只對當前事務可見,對其他事務不可見,因此在事務提交后可以直接刪除,無需進行purge操作。
- update undo log:更新Undo日志是指在更新或刪除操作中生成的Undo日志。更新Undo日志可能需要提供MVCC機制,因此不能在事務提交時就立即刪除。相反,它們會在提交時放入Undo日志鏈表中,并等待purge線程進行最終的刪除。刪除操作只是設置一下老記錄的 DELETED_BIT,并不真正將過時的記錄刪除,為了節省磁盤空間,InnoDB有專門的purge線程來清理 DELETED_BIT 為true的記錄。
注意:由于查詢操作(SELECT)并不會修改任何記錄,所以在查詢操作執行時,并不需要記錄相應的 undo log 。Tzb28資訊網——每日最新資訊28at.com
不同事務或者相同事務對同一記錄行的修改,會使該記錄行的 undo log 成為一條鏈表,鏈首就是最新的記錄,鏈尾就是最早的舊記錄Tzb28資訊網——每日最新資訊28at.com
舉個例子,比如有個事務A插入了一條新記錄:insert into user(id, name) values(1, "小明')Tzb28資訊網——每日最新資訊28at.com
現在來了一個事務B對該記錄的name做出了修改,改為 "小王"。Tzb28資訊網——每日最新資訊28at.com
在事務B修改該行數據時,數據庫會先對該行加排他鎖,然后把該行數據拷貝到 undo log 中作為舊記錄,即在 undo log 中有當前行的拷貝副本.Tzb28資訊網——每日最新資訊28at.com
拷貝完畢后,修改該行name為 "小王,并且修改隱藏字段的事務ID為當前事務B的ID, 并將回滾指針指向拷貝到 undo log 的副本記錄,即表示我的上一個版本就是它,事務提交后,釋放鎖。Tzb28資訊網——每日最新資訊28at.com
圖片Tzb28資訊網——每日最新資訊28at.com
此時又來了個事務C修改同一個記錄,將name修改為 "小紅"。Tzb28資訊網——每日最新資訊28at.com
在事務C修改該行數據時,數據庫也先為該行加鎖,然后把該行數據拷貝到 undo log 中,作為舊記錄,發現該行記錄已經有 undo log 了,那么最新的舊數據作為鏈表的表頭,插在該行記錄的 undo log 最前面,如下圖:Tzb28資訊網——每日最新資訊28at.com
圖片Tzb28資訊網——每日最新資訊28at.com
關于 DB_ROLL_PTR 與 Undo日志 的配合工作,具體流程如下:Tzb28資訊網——每日最新資訊28at.com
- 在更新或刪除操作之前,MySQL會將舊值寫入Undo日志中。
- 當事務需要回滾時,MySQL會根據事務的Undo日志記錄,通過 DB_ROLL_PTR 找到對應的Undo日志。
- 根據Undo日志中記錄的舊值,MySQL將舊值恢復到相應的數據行中,實現數據的回滾操作。
比方說現在想回滾到事務B,name值為 "小王" 的時候,只需通過 DB_ROLL_PTR 順著列表找到對應的 Undo日志,將舊值恢復到數據行即可。Tzb28資訊網——每日最新資訊28at.com
通過 DB_ROLL_PTR 和 Undo日志 的配合工作,MySQL能夠有效地管理事務的一致性和隔離性。Undo日志的使用也使得MySQL能夠支持MVCC,從而提供了高并發環境下的讀取一致性和事務隔離性。Tzb28資訊網——每日最新資訊28at.com
版本鏈
在MVCC中,對于每次更新操作,舊值會被保存到一條undo日志中,即使它是該記錄的舊版本。隨著更新次數的增加,所有的版本都會通過roll_pointer屬性連接成一個鏈表,稱之為版本鏈。Tzb28資訊網——每日最新資訊28at.com
版本鏈的頭節點代表當前記錄的最新值。此外,每個版本還包含生成該版本的事務ID。Tzb28資訊網——每日最新資訊28at.com
Read View
一致性視圖,全稱 Read View ,是用來判斷版本鏈中的哪個版本對當前事務是可見的Tzb28資訊網——每日最新資訊28at.com
Read View 說白了就是事務進行快照讀操作時候生成的讀視圖(Read View),在該事務執行快照讀的那一刻,會生成數據庫系統當前的一個快照,記錄并維護系統當前活躍事務的ID(每個事務開啟時,都會被分配一個ID,這個ID是遞增的)。Tzb28資訊網——每日最新資訊28at.com
這里有一點要注意一下:Read View只針對 RC 和 RR級別Tzb28資訊網——每日最新資訊28at.com
Read Uncommitted(RU)和 Serializable(串行化)是兩個特殊的隔離級別,它們不需要使用 Read View 的主要原因是:Tzb28資訊網——每日最新資訊28at.com
- Read Uncommitted(RU)隔離級別:在 RU 隔離級別下,事務可以讀取其他事務尚未提交的數據,即臟讀。這意味著不需要通過 Read View 來限制訪問范圍,事務可以自由地讀取其他事務的未提交數據。由于沒有對可見性進行嚴格控制,因此不需要創建或使用 Read View。
- Serializable(串行化)隔離級別:在 Serializable 隔離級別下,事務具有最高的隔離性,確保每次讀取都能看到一致的快照。為了實現這種隔離級別,MySQL使用鎖機制來保證事務之間的串行執行。由于事務按順序執行,并且不允許并發操作,所以不需要使用 Read View 進行可見性判斷。
Read Uncommitted 和 Serializable 隔離級別下的事務規則不涉及基于 Read View 的可見性判斷。RU 允許臟讀,而 Serializable 則通過鎖機制保證串行執行。因此,在這兩個隔離級別下,不需要創建或使用 Read View。Tzb28資訊網——每日最新資訊28at.com
Read View 可見性原則
Read View 遵循一個可見性原則,將要被修改的數據的 DB_TRX_ID 取出來,與系統當前其他活躍事務的ID去對比。Tzb28資訊網——每日最新資訊28at.com
如果 DB_TRX_ID 跟 Read View 的屬性做了某些比較,不符合可見性,那就通過 DB_ROLL_PTR 回滾指針去取出 Undo Log 中的 DB_TRX_ID 再比較。Tzb28資訊網——每日最新資訊28at.com
即遍歷鏈表的 DB_TRX_ID (從鏈首到鏈尾,即從最近的一次修改查起),直到找到滿足特定條件的 DB_TRX_ID,那么這個 DB_TRX_ID 所在的記錄就是當前事務能看見的最新老版本。Tzb28資訊網——每日最新資訊28at.com
Read View 會維護以下幾個字段:Tzb28資訊網——每日最新資訊28at.com
字段Tzb28資訊網——每日最新資訊28at.com | 含義Tzb28資訊網——每日最新資訊28at.com |
m_idsTzb28資訊網——每日最新資訊28at.com | Read View 創建時其他未提交的活躍事務 ID 列表。創建 Read View 時,將當前未提交事務 ID 記錄下來,后續即使它們修改了記錄行的值,對于當前事務也是不可見的。m_ids 不包括當前事務自己和已提交的事務(正在內存中)。Tzb28資訊網——每日最新資訊28at.com
|
m_creator_trx_idTzb28資訊網——每日最新資訊28at.com | 創建該 Read View 的事務 ID。Tzb28資訊網——每日最新資訊28at.com |
m_low_limit_idTzb28資訊網——每日最新資訊28at.com | 目前出現過的最大的事務 ID+1,即下一個將被分配的事務 ID。大于等于這個 ID 的數據版本均不可見。Tzb28資訊網——每日最新資訊28at.com |
m_up_limit_idTzb28資訊網——每日最新資訊28at.com | 活躍事務列表 m_ids 中最小的事務 ID,如果 m_ids 為空,則 m_low_limit_id 為m_up_limit_id 。小于這個 ID 的數據版本均可見。Tzb28資訊網——每日最新資訊28at.com |
Read View 可見性具體判斷如下:Tzb28資訊網——每日最新資訊28at.com
- 如果被訪問版本的 DB_TRX_ID 屬性值與 Read View 中的 m_creator_trx_id 值相同,表示當前事務正在訪問自己所修改的記錄,因此該版本可以被當前事務訪問。
- 如果被訪問版本的 DB_TRX_ID 屬性值小于 Read View 中的 m_up_limit_id 值,說明生成該版本的事務在當前事務生成 Read View 之前已經提交,因此該版本可以被當前事務訪問。
- 如果被訪問版本的 DB_TRX_ID 屬性值大于或等于 Read View 中的 m_low_limit_id 值,說明生成該版本的事務在當前事務生成 Read View 之后才提交,因此該版本不能被當前事務訪問。
- 如果被訪問版本的 DB_TRX_ID 屬性值位于 Read View 的 m_up_limit_id 和 m_low_limit_id 之間(包括邊界),則需要進一步檢查 DB_TRX_ID 是否在m_ids 列表中。如果在列表中,說明在創建ReadView時生成該版本的事務仍處于活躍狀態,因此該版本不能被訪問;如果不在列表中,說明在創建 Read View 時生成該版本的事務已經提交,因此該版本可以被訪問。
事務可見性示意圖:Tzb28資訊網——每日最新資訊28at.com
圖片Tzb28資訊網——每日最新資訊28at.com
RC 和 RR 下的 Read View
RC 和 RR 下生成 Read View 的時機是有所差異的:Tzb28資訊網——每日最新資訊28at.com
- RC:每次 SELECT 數據前都生成一個ReadView。
- RR:只在第一次讀取數據時生成一個ReadView,后面會復用第一次生成的。
正因為RC 和 RR生成 Read View 的時機不同,導致兩個級別下看到的數據會不一致。Tzb28資訊網——每日最新資訊28at.com
舉例說明,假設數據初始狀態如下:Tzb28資訊網——每日最新資訊28at.com
有 A,B,C 三個事務,執行順序如下:Tzb28資訊網——每日最新資訊28at.com
Tzb28資訊網——每日最新資訊28at.com
| 事務A(事務ID: 100)Tzb28資訊網——每日最新資訊28at.com | 事務B(事務ID: 200)Tzb28資訊網——每日最新資訊28at.com | 事務C(事務ID: 300)Tzb28資訊網——每日最新資訊28at.com |
T1Tzb28資訊網——每日最新資訊28at.com | beginTzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| Tzb28資訊網——每日最新資訊28at.com
|
T2Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| beginTzb28資訊網——每日最新資訊28at.com | beginTzb28資訊網——每日最新資訊28at.com |
T3Tzb28資訊網——每日最新資訊28at.com | update user set name="小王" where id=1Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| Tzb28資訊網——每日最新資訊28at.com
|
T4Tzb28資訊網——每日最新資訊28at.com | update user set name="小紅" where id=1Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| select * from user where id = 1Tzb28資訊網——每日最新資訊28at.com |
T5Tzb28資訊網——每日最新資訊28at.com | commitTzb28資訊網——每日最新資訊28at.com | update user set name="小黑" where id=1Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
|
T6Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| update user set name="小白" where id=1Tzb28資訊網——每日最新資訊28at.com | select * from user where id = 1Tzb28資訊網——每日最新資訊28at.com |
T7Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| commitTzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
|
T8Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| Tzb28資訊網——每日最新資訊28at.com
| select * from user where id = 1Tzb28資訊網——每日最新資訊28at.com |
T9Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| Tzb28資訊網——每日最新資訊28at.com
| commitTzb28資訊網——每日最新資訊28at.com |
T10Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| Tzb28資訊網——每日最新資訊28at.com
| Tzb28資訊網——每日最新資訊28at.com
|
RC 下的 Read View
T4時刻Tzb28資訊網——每日最新資訊28at.com
我們來看 T4 時刻的情況,此時 事務A 和 事務B 都還沒提交,所以活躍的事務ID,即 m_ids 為:[100,200],四個字段的值分別如下:Tzb28資訊網——每日最新資訊28at.com
字段Tzb28資訊網——每日最新資訊28at.com | 值Tzb28資訊網——每日最新資訊28at.com |
m_idsTzb28資訊網——每日最新資訊28at.com | [100,200]Tzb28資訊網——每日最新資訊28at.com |
m_creator_trx_idTzb28資訊網——每日最新資訊28at.com | 300Tzb28資訊網——每日最新資訊28at.com |
m_low_limit_idTzb28資訊網——每日最新資訊28at.com | 400Tzb28資訊網——每日最新資訊28at.com |
m_up_limit_idTzb28資訊網——每日最新資訊28at.com | 100Tzb28資訊網——每日最新資訊28at.com |
T4時刻的版本鏈如下:Tzb28資訊網——每日最新資訊28at.com
圖片Tzb28資訊網——每日最新資訊28at.com
依據我們之前說的可見性原則,事務C最終看到的應該是 name = "小明" 的數據,理由如下:Tzb28資訊網——每日最新資訊28at.com
最新記錄的 DB_TRX_ID 為 100,既不小于 m_up_limit_id,也不大于 m_low_limit_id,也不等于 m_creator_trx_id。Tzb28資訊網——每日最新資訊28at.com
落在了黃區:Tzb28資訊網——每日最新資訊28at.com
圖片Tzb28資訊網——每日最新資訊28at.com
DB_TRX_ID 存在于 m_ids 列表中,故不可見,順著版本鏈繼續往下。Tzb28資訊網——每日最新資訊28at.com
根據 DB_ROLL_PTR 找到 undo log 中的前一版本記錄,前一條記錄的 DB_TRX_ID 還是 100,還是不可見,繼續往下。Tzb28資訊網——每日最新資訊28at.com
繼續找前一條 DB_TRX_ID為 1,滿足 1 < m_up_limit_id,可見,所以事務C 查詢到數據為 name = "小明" 。Tzb28資訊網——每日最新資訊28at.com
T6時刻Tzb28資訊網——每日最新資訊28at.com
T6時候的版本鏈如下:Tzb28資訊網——每日最新資訊28at.com
圖片Tzb28資訊網——每日最新資訊28at.com
T6時刻,會再次生成新的 Read View,四個字段的值分別如下:Tzb28資訊網——每日最新資訊28at.com
字段Tzb28資訊網——每日最新資訊28at.com | 值Tzb28資訊網——每日最新資訊28at.com |
m_idsTzb28資訊網——每日最新資訊28at.com | [200]Tzb28資訊網——每日最新資訊28at.com |
m_creator_trx_idTzb28資訊網——每日最新資訊28at.com | 300Tzb28資訊網——每日最新資訊28at.com |
m_low_limit_idTzb28資訊網——每日最新資訊28at.com | 400Tzb28資訊網——每日最新資訊28at.com |
m_up_limit_idTzb28資訊網——每日最新資訊28at.com | 200Tzb28資訊網——每日最新資訊28at.com |
根據可見性原則,最終T6時刻事務C 查詢到數據為 name = "小紅" 。Tzb28資訊網——每日最新資訊28at.com
T8時刻Tzb28資訊網——每日最新資訊28at.com
T8時刻的版本鏈和T6時刻是一致的,不同的是 Read View,因為T8時刻會再生成一個 Read View,四個字段的值分別如下:Tzb28資訊網——每日最新資訊28at.com
字段Tzb28資訊網——每日最新資訊28at.com | 值Tzb28資訊網——每日最新資訊28at.com |
m_idsTzb28資訊網——每日最新資訊28at.com | []Tzb28資訊網——每日最新資訊28at.com |
m_creator_trx_idTzb28資訊網——每日最新資訊28at.com | 300Tzb28資訊網——每日最新資訊28at.com |
m_low_limit_idTzb28資訊網——每日最新資訊28at.com | 400Tzb28資訊網——每日最新資訊28at.com |
m_up_limit_idTzb28資訊網——每日最新資訊28at.com | 400Tzb28資訊網——每日最新資訊28at.com |
根據可見性原則,最終T8時刻事務C 查詢到數據為 name = "小白" 。Tzb28資訊網——每日最新資訊28at.com
總結一下,事務C在 RC 級別下各個時刻看到的數據如下:Tzb28資訊網——每日最新資訊28at.com
時刻Tzb28資訊網——每日最新資訊28at.com | nameTzb28資訊網——每日最新資訊28at.com |
T4Tzb28資訊網——每日最新資訊28at.com | 小明Tzb28資訊網——每日最新資訊28at.com |
T6Tzb28資訊網——每日最新資訊28at.com | 小紅Tzb28資訊網——每日最新資訊28at.com |
T8Tzb28資訊網——每日最新資訊28at.com | 小白Tzb28資訊網——每日最新資訊28at.com |
下面我們來看看,RR 級別下的表現是如何的。Tzb28資訊網——每日最新資訊28at.com
RR 下的 Read View
(RR 的版本鏈和 RC 的版本鏈是一致的,區別在于 Read View)Tzb28資訊網——每日最新資訊28at.com
T4時刻Tzb28資訊網——每日最新資訊28at.com
T4 時刻的情況,和 R C的情況是一致的:Tzb28資訊網——每日最新資訊28at.com
字段Tzb28資訊網——每日最新資訊28at.com | 值Tzb28資訊網——每日最新資訊28at.com |
m_idsTzb28資訊網——每日最新資訊28at.com | [100,200]Tzb28資訊網——每日最新資訊28at.com |
m_creator_trx_idTzb28資訊網——每日最新資訊28at.com | 300Tzb28資訊網——每日最新資訊28at.com |
m_low_limit_idTzb28資訊網——每日最新資訊28at.com | 400Tzb28資訊網——每日最新資訊28at.com |
m_up_limit_idTzb28資訊網——每日最新資訊28at.com | 100Tzb28資訊網——每日最新資訊28at.com |
根據可見性原則,最終T4時刻事務C 查詢到數據為 name = "小明" ,和 RC 的T4時刻是一致的。Tzb28資訊網——每日最新資訊28at.com
T6時刻Tzb28資訊網——每日最新資訊28at.com
RR 級別會復用 Read View,所以T6時刻也是:Tzb28資訊網——每日最新資訊28at.com
字段Tzb28資訊網——每日最新資訊28at.com | 值Tzb28資訊網——每日最新資訊28at.com |
m_idsTzb28資訊網——每日最新資訊28at.com | [100,200]Tzb28資訊網——每日最新資訊28at.com |
m_creator_trx_idTzb28資訊網——每日最新資訊28at.com | 300Tzb28資訊網——每日最新資訊28at.com |
m_low_limit_idTzb28資訊網——每日最新資訊28at.com | 400Tzb28資訊網——每日最新資訊28at.com |
m_up_limit_idTzb28資訊網——每日最新資訊28at.com | 100Tzb28資訊網——每日最新資訊28at.com |
根據可見性原則,T6時刻我們發現事務C查詢到的數據還是 name = "小明" 。Tzb28資訊網——每日最新資訊28at.com
繼續看T8時刻。Tzb28資訊網——每日最新資訊28at.com
T8時刻Tzb28資訊網——每日最新資訊28at.com
T8時刻繼續復用先前的 Read View。Tzb28資訊網——每日最新資訊28at.com
根據可見性原則,T8時刻事務C查詢到的數據依舊是 name = "小明" 。Tzb28資訊網——每日最新資訊28at.com
小結
我們將事務C在 RC 和 RR 級別下看到的數據,放到一塊來對比下:Tzb28資訊網——每日最新資訊28at.com
時刻Tzb28資訊網——每日最新資訊28at.com | RCTzb28資訊網——每日最新資訊28at.com | RRTzb28資訊網——每日最新資訊28at.com |
T4Tzb28資訊網——每日最新資訊28at.com | 小明Tzb28資訊網——每日最新資訊28at.com | 小明Tzb28資訊網——每日最新資訊28at.com |
T6Tzb28資訊網——每日最新資訊28at.com | 小紅Tzb28資訊網——每日最新資訊28at.com | 小明Tzb28資訊網——每日最新資訊28at.com |
T8Tzb28資訊網——每日最新資訊28at.com | 小白Tzb28資訊網——每日最新資訊28at.com | 小明Tzb28資訊網——每日最新資訊28at.com |
可以看出二者由于生成 Read View 的時機不同,導致在各個時刻看到的數據會存在差異。Tzb28資訊網——每日最新資訊28at.com
回過頭來看 RC 和 RR 隔離級別的定義,會有種恍然大悟的感覺:Tzb28資訊網——每日最新資訊28at.com
- 讀已提交(Read Committed):事務只能讀取到已經提交的數據。
- 可重復讀(Repeatable Read):事務在整個事務期間保持一致的快照視圖,不受其他事務的影響。
總之在 RC 隔離級別下,每個快照讀都會生成并獲取最新的 Read View;而在 RR 隔離級別下,則是只在第一個快照讀創建Read View,之后的快照讀獲取的都是同一個Read ViewTzb28資訊網——每日最新資訊28at.com
RR 級別下能否防止幻讀
嚴謹的說,RR 級別下只能防止部分幻讀Tzb28資訊網——每日最新資訊28at.com
首先,幻讀通常指的是在同一個事務中,第二次查詢發現了新增加的行,而第一次查詢并沒有返回這些新增加的行。Tzb28資訊網——每日最新資訊28at.com
通過前面的例子,我們也看到了,在 RR 隔離級別下,由于一致性視圖的存在,如果其他事務插入了新的行,在同一個事務中進行多次查詢,這些新增的行將會被包含在事務的一致性視圖中,確實可以避免部分幻讀場景。Tzb28資訊網——每日最新資訊28at.com
這里注意一下:MVCC解決的只是 RR 級別下快照讀的幻讀問題,而當前讀的幻讀問題則是通過臨鍵鎖來解決的。也就是說 RR 級別下是通過 MVCC+臨鍵鎖 來解決大部分幻讀問題的。Tzb28資訊網——每日最新資訊28at.com
為什么說是部分解決?看下面這個例子:Tzb28資訊網——每日最新資訊28at.com
Tzb28資訊網——每日最新資訊28at.com
| 事務ATzb28資訊網——每日最新資訊28at.com | 事務BTzb28資訊網——每日最新資訊28at.com |
T1Tzb28資訊網——每日最新資訊28at.com | beginTzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
|
T2Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| beginTzb28資訊網——每日最新資訊28at.com |
T3Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| select * from userTzb28資訊網——每日最新資訊28at.com |
T4Tzb28資訊網——每日最新資訊28at.com | insert into user(id, name) values(2, "小張')Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
|
T5Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| select * from user for updateTzb28資訊網——每日最新資訊28at.com |
T6Tzb28資訊網——每日最新資訊28at.com | commitTzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
|
T7Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| commitTzb28資訊網——每日最新資訊28at.com |
假設數據初始狀態如下:Tzb28資訊網——每日最新資訊28at.com
圖片Tzb28資訊網——每日最新資訊28at.com
T3時刻看到的數據只有一條 name = "小明",而T5時刻,由于 select * from user for update 使用的是當前讀,讀取的是最新的數據版本,T5時刻查詢出來的數據是兩條,name 分別為 "小明" 和 "小張"。Tzb28資訊網——每日最新資訊28at.com
理解了上面的例子之后,再看下面這個例子:Tzb28資訊網——每日最新資訊28at.com
Tzb28資訊網——每日最新資訊28at.com
| 事務ATzb28資訊網——每日最新資訊28at.com | 事務BTzb28資訊網——每日最新資訊28at.com |
T1Tzb28資訊網——每日最新資訊28at.com | beginTzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
|
T2Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| beginTzb28資訊網——每日最新資訊28at.com |
T3Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| select * from userTzb28資訊網——每日最新資訊28at.com |
T4Tzb28資訊網——每日最新資訊28at.com | insert into user(id, name) values(2, "小張')Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
|
T5Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| update user set name="小陳" where id=2Tzb28資訊網——每日最新資訊28at.com |
T6Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| select * from userTzb28資訊網——每日最新資訊28at.com |
T7Tzb28資訊網——每日最新資訊28at.com | commitTzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
|
T8Tzb28資訊網——每日最新資訊28at.com | Tzb28資訊網——每日最新資訊28at.com
| commitTzb28資訊網——每日最新資訊28at.com |
UPDATE 語句也是當前讀,也會發生幻讀問題,最終看到的數據是name 分別為 "小明" 和 "小陳"。Tzb28資訊網——每日最新資訊28at.com
這里發生幻讀的原因,和上面的例子是一樣的,本質都是在一個事務中,即使用了快照讀又使用了當前讀,RR 級別下無法預防此種情況,所以說 RR 級別下無法完全解決幻讀問題。Tzb28資訊網——每日最新資訊28at.com
總結
綜上所述,MVCC 是一種強大的并發控制機制,在高并發環境中起著重要的作用。通過了解 MVCC 的原理和實現流程,我們可以更好地理解 MySQL 的并發控制機制,理解 MVCC 的原理對于接觸 MySQL 的開發人員來說是必不可少的知識點。Tzb28資訊網——每日最新資訊28at.com
本文鏈接:http://www.tebozhan.com/showinfo-26-59679-0.html全網最詳細MVCC講解,一篇看懂
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 初步利用Ansible實現批量服務器自動化管理
下一篇: 在Go編程中調用外部命令的幾種場景