很久以前寫過事務原子性、一致性、永續性的實現原理,這篇文章聊一下Innodb事務的隔離性的實現原理,預設隔離級別是可重複讀。主要還是講整體脈絡,脈絡清晰後,細節大家可以自行補充。
1。知識點
要明白事務隔離性的實現原理,有幾個知識點必須掌握。
1。1快照讀
快照讀
:也稱為一致非鎖定讀或一致性讀,即不加鎖的非阻塞讀
前提
:快照讀的前提是隔離級別不是序列級別,序列級別下的快照讀會退化成當前讀
優點
:基於提高併發效能的考慮,避免了加鎖操作,降低了開銷
實現
:快照讀的實現是基於多版本併發控制,即MVCC
效果
:既然是基於多版本,即
快照讀可能讀到的並不一定是資料的最新版本,而有可能是之前的歷史版本
語法
:一般的select就是快照讀
1。2當前讀
效果
:
讀取的是記錄的最新版本
實現
:讀取時還要保證其他併發事務不能修改當前記錄,會對讀取的記錄進行加鎖
語法
:select lock in share mode(共享鎖), select for update ; update, insert ,delete(排他鎖)。全是需要加鎖的。
1。3事務ID
InnoDB 裡面每個事務有一個
唯一
的事務 ID,叫作 transaction id。它是在事務開始的時候向 InnoDB 的事務系統申請的,是按申請順序
嚴格遞增
的。
1。4Undo Log
在InnoDB redo、undo、binlog,是如何合作的中曾提到過Undo Log。對每行資料進行操作之前都會記錄Undo Log,目的是能將資料進行回滾。
同一個事務對資料進行多次修改或者多個事務對同一個資料進行修改,這些
修改會按照時間順序連成鏈
,所以透過undo log可以發現數據修改的歷史。
Undo Log不是一直存在的。Undo Log主要分為兩種:
insert undo log
:代表事務在insert新記錄時產生的undo log,只在事務回滾時需要,並且在事務提交後可以被立即丟棄
update undo log
:事務在進行update或delete時產生的undo log; 不僅在事務回滾時需要,在快照讀時也需要;所以不能隨便刪除,只有在快照讀或事務回滾不涉及該日誌時,對應的日誌才會被purge執行緒統一清除
1。5行結構
表中每一行的資料,除了我們自定義的欄位外,還有資料庫隱式定義的DB_TRX_ID,DB_ROLL_PTR,DB_ROW_ID等欄位。
DB_TRX_ID:6byte,最近修改(修改/插入)
事務ID
。記錄建立這條記錄/最後一次修改該記錄的事務ID
DB_ROLL_PTR:7byte,回滾指標,指向這條
記錄的上一個版本
(儲存於rollback segment裡),本質上利用undo log的能力
DB_ROW_ID:6byte,隱含的自增ID(隱藏主鍵),如果資料表沒有主鍵,InnoDB會自動以DB_ROW_ID產生一個聚簇索引
1。6一致性檢視(read-view)
1。6。1定義
事務執行的
快照讀的那一刻
,會生成資料庫系統當前的一個快照,注意,這個快照是基於整庫的。記錄並維護系統當前活躍事務的ID,裡面事務 ID 的最小值記為低水位,當前系統裡面已經建立過的事務 ID 的最大值加 1記為高水位。他們組成了當前事務的一致性檢視(read-view)。
1。6。2生成時機
begin/start transaction 命令並不是一個事務的起點,在執行到它們之後的第一個操作InnoDB 表的語句,
事務才真正啟動
。如果你想要馬上啟動一個事務,可以使用 start transaction with consistent snapshot 這個命令。
第一種啟動方式,一致性檢視是在第
執行第一個快照讀語句時建立的
,如select;
第二種啟動方式,一致性檢視是在執行 start transaction with consistent snapshot 時建立的。
1。7MVCC
MVCC,全稱Multi-Version Concurrency Control,即多版本併發控制。MVCC是一種併發控制的方法,一般在資料庫管理系統中,實現對資料庫的併發訪問,在程式語言中實現事務記憶體。
2。資料可見性規則
根據上面提到的Undo Log、一致性檢視,來看一下資料的可見性規則。
如果落在綠色部分,表示這個版本是已提交的事務,這個資料是可見的;
如果事務id是自己的值,表示資料是可見的;
如果落在紅色部分,表示這個版本是由將來啟動的事務生成的,是肯定不可見的;
如果落在黃色部分,那就包括兩種情況a。 若 row trx_id 在陣列中,表示這個版本是由還沒提交的事務生成的,不可見;b。 若 row trx_id 不在陣列中,表示這個版本是已經提交了的事務生成的,可見。
如果當前的版本不可見,則根據連結串列尋找上一個版本,再次判斷可見性規則,直到找到可見的資料。
按照這個流程,大家便能夠清楚的知道事務讀取的值會是哪一個,同時也明白事務隔離性是怎樣實現的。
也能看出來所謂的快照讀並不是將所有資料複製一份,只是透過可見性規則來進行限制的。
在可見性規則上,我們看這個例子。表中有值(id:1,k:1),有三個事務進行操作,問事務B和事務A透過select獲取的值分別是多少?
3。行鎖
事務B查到的是3,事務A查到的是1。
事務A查到1比較容易理解,根據可見性規則,事務B和事務C‘對事務A而言都屬於未開始事務,所以等事務A查詢的時候,會不斷回溯,找到(1,1)。
事務B比較有意思,查到的不應該也是1嗎,為什麼是3?這裡面有兩個細節。
在講當前讀的時候,select lock in share mode(共享鎖), select for update ; update, insert ,delete(排他鎖)都是當前讀,對修改的那行資料都加了鎖。所以必須事務C’提交完後,事務B的update才能繼續執行,否則事務B
阻塞
。
update先當前讀,後寫,行資料被真正的進行了修改,行資料中的DB_TRX_ID已經是事務B的事務ID,根據可見性規則,事務B查詢到的值變為了3。
所以能夠推論出兩個例子:
如果事務B在操作update之前,執行一次select k from t where id=1,查到的值為1。這種情況經常會讓大家認為快照讀失效了,其實這是符合資料可見性規則的。
如果事務A的select改為select k from t where id=1 lock in share mode,查到的值是3。當然,只有事務B提交後, lock in share mode才能執行,否則會被阻塞。
4。總結
可重複讀的核心就是一致性讀(consistent read);而事務更新資料的時候,只能用當前讀。如果當前的記錄的行鎖被其他事務佔用的話,就需要進入鎖等待。
一致性讀、當前讀和行鎖串聯起事務的隔離性。
資料
MVCC多版本併發控制
Mysql-InnoDB 事務-一致性讀(快照讀)
一篇文章帶你掌握mysql的一致性檢視(MVCC)
MySQL45講
最後
大家如果喜歡我的文章,可以關注我的公眾號(程式設計師麻辣燙)
我的個人部落格為:https://shidawuhen。github。io/
往期文章回顧:
設計模式
招聘
思考
儲存
算法系列
讀書筆記
小工具
架構
網路
Go語言