MySQL InnoDB 事務隔離級別的實現原理

今天介紹下,在 MySQLInnoDB 存儲引擎中,事務隔離是如何實現的。sql

InnoDB 裏面每一個事務有一個惟一的事務 ID,叫做 transaction id。它是在事務開始的時候向 InnoDB 的事務系統申請的,是按申請順序嚴格遞增的。數據庫

對於數據庫的每行記錄,都會有三個隱藏字段:db_trx_id (事務 id)db_roll_pt (回滾指針)delete_flag(刪除標記)。— 有懂的朋友,還望別細糾,其實 delete_flag 是在頭信息中,這裏是爲了方便理解數組

對於 DML 操做來講:ui

  • INSERT:建立一條數據,db_trx_id 的值爲當前事務 id, db_roll_ptnull
  • UPDATE:複製一行數據,將當前複製後這一行的 db_trx_id 置爲當前事務的 iddb_roll_pt 是一個指針,指向複製前的那一條的。
  • DELETE:複製一行數據,將當前複製後這一行的 db_trx_id 置爲當前事務的 iddb_roll_pt 是一個指針,指向複製前的那一條的。並把 delete_flag 置爲 true

咱們會用此語句建表及初始化數據,用於下面舉例:spa

CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `k` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

insert into t(id, k) values(1, 1);
複製代碼

數據初始狀態爲:3d

Repeatable Read 可重複讀

如當前的隔離界別爲 Repeatable Read ,下面是 SQL 的執行過程:指針

那麼對於第 8,10,12,13 行來講,查詢的結果應該是什麼呢?code

結果應該分別是:2,1,3,1 。cdn

下面咱們來逐步回放,MySQL 底層是如何實現這整個過程的:blog

  • 第 1 行:表示每一個事務的 ID 號,其中 read view 取的是全部當前活躍的事務 ID 數組,活躍指的是,已開啓並生成事務 ID 但未提交的事務。max id 取的是,目前爲止,最大的事務 ID,不管是否已提交。咱們還稱 read view 數組中,最小的值爲 min id

  • 第 2 - 4 行:表示分別開啓使用,並建立此事務的 read viewmax id,要注意的是,這裏我並無使用 begin/start transaction 來開啓事務,是由於它們並不會立刻建立 read viewmax id,而是在執行第一條 select 語句後,來進行建立的。

  • 第 5 行爲修改 k 的值,自增 1,按照上面所說的規則,修改後:

  • 第 6 行,提交 ID 爲 102 的事務。

  • 第 7 行執行了一個簡單查詢,未手動開啓事務,但也會自動開啓並生成 read viewmax id,分別爲 read-view: [100, 101]max-id: 103

此時會根據查詢規則,進行查找,規則以下:

  1. 若是數據的 db_trx_id < min id ,則說明數據在開啓當前事務前已提交的,內容可見。

  2. 若是數據的 db_trx_id > max id ,則說明數據在此事務啓動後生成的,內容不可見。

  3. 若是數據的 min id <= db_trx_id <= max id ,則還分爲兩種狀況:

    3.1 若 db_trx_idread view 的數組中,表示這個版本是由還沒提交的事務生成的,不可見,但若是是本身的事務,則可見。

    3.2. 若不在數據中,則表示這個版本是已經提交了的事務生成的,可見。

示意圖以下:

當前的事務的一致性視圖爲 read view: [100, 101]max id: 103,那麼根據這個規則,在上面的數據鏈中查詢數據,從最新的藍色,開始找,找到第一個數據的 db_trx_id 爲 102,符合規則 3.2 屬於可見範圍,查詢結果爲 2。

  • 第 8 行,當前的事務的一致性視圖爲 read view: [100, 101]max id: 101一樣根據規則,第一個數據的 db_trx_id 爲 102,符合規則 2,不可見,那麼根據指針 db_roll_pt 繼續查找,找到 db_trx_id 爲 10 的數據,符合規則 1,數據可見,查詢結果爲 1。

  • 第 9 行,修改 k 的值,自增 1,按照上面所說的規則,修改後:

  • 第 10 行,當前的事務的一致性視圖爲 read view: [100]max id: 100 一樣根據規則,第一個數據的 db_trx_id 爲 100,符合規則 3.1,在 read view 數組中,可是此 id 爲當前事務 id,因此但是可見的,查詢結果爲 3。

  • 第 11 行,當前的事務的一致性視圖爲 read view: [100, 101]max id: 101 一樣根據規則,第一個數據的 db_trx_id 爲 100,符合規則 3.1,在 read view 中,可是此 id 不爲當前事務 id,因此內容可見的,那麼根據指針 db_roll_pt 繼續查找,找到 db_trx_id 爲 102 的數據,符合規則 2,不可見,繼續根據指針 db_roll_pt 查找,找到 db_trx_id 爲 10 的數據,符合規則 1,數據可見,查詢結果爲 1。

  • 第 12 - 13 行,爲提交事務語句。

Read Committed 讀已提交

處於 Read Committed 讀已提交 也可套用上面的規則,不過一致性視圖: read viewmax id 的建立時機,是每一條 select 語句時從新生成。你根據上面的內容,能夠本身動手試驗下讀已提交。

相關文章
相關標籤/搜索