溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

MySQL中的MVCC是怎么樣的

發布時間:2021-10-25 09:56:08 來源:億速云 閱讀:156 作者:柒染 欄目:大數據

MySQL中的MVCC是怎么樣的,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。

前言

MySQL 是目前流行的開源數據庫之一,各大公司都使用 MySQL 作為自家的關系型數據庫,但是 MySQL 作為一個數據庫而言,基本使用是非常簡單的,只要會一點點建表語句(可以使用工具建表),一點點查詢語句就可以使用 MySQL 來存儲數據了。

這種沒有靈魂的操作,對于很多初學者來說也許已經是家常便飯了。但是對于一些已經有開發經驗的人來說,這是遠遠不夠的。你必須要學習很多數據庫相關的知識,而這一篇就是徹底來剖析 MySQL 中的 MVCC 是如何實現的??赐赀@篇文章,你就可以知道各種隔離級別之下,MVCC 的作用是什么?MVCC 在什么時候會使用?怎么使用?

示例表

CREATE TABLE `test`.`Untitled`  (
 `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
 `phone` char(11) NOT NULL,
 `name` varchar(255) NOT NULL,
 `age` int(3) NOT NULL,
 `country` varchar(255) NOT NULL,
 PRIMARY KEY (`id`) USING BTREE,
 UNIQUE INDEX `uk_phone`(`phone`) USING BTREE,
 INDEX `idx_name`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
復制代碼
insert into person values (null, '1351111111', 'any', 20, '蜀');
insert into person values (null, '1351111112', 'bat', 21, '吳');
復制代碼
idphonenameagecountry
11351111111any20
21351111112bat21

MVCC

MVCC 是無鎖操作的一種實現方式,無鎖就是沒有鎖。無鎖能夠大幅度提高數據庫的并發性。它最基本的表現形式就是一致性非鎖定讀,通過 MVCC (多版本并發控制)來實現。MVCC 主要又是依靠 Read View 來實現的。

在數據庫中的每一條記錄實際都會存在三個隱藏列:

  • DB_TRX_ID:該列表示此記錄的事務 ID

  • DB_ROLL_PTR:該列表示一個指向回滾段的指針,實際就是指向該記錄的一個版本鏈

  • DB_ROW_ID:記錄的 ID,如果有指定主鍵,那么該值就是主鍵。如果沒有主鍵,那么就會使用定義的第一個唯一索引。如果沒有唯一索引,那么就會默認生成一個值。

start transaction;
update person set age = 22 where id = 1;
update person set name = 'out' where id = 1;
commit;
復制代碼

當執行完上面兩條語句之后,但是還沒有提交事務之前,它的版本鏈是沒有異常的。

而 Read View 是用來判斷每一個讀取語句有資格讀取版本鏈中的哪個記錄。所以在在讀取之前,都會生成一個 Read View。然后根據生成的 Read View 再去讀取記錄。

在事務中,只有執行插入、更新、刪除操作時才會分配到一個事務 id。如果事務只是一個單純的讀取事務,那么它的事務 id 就是默認的 0。

Read View 的結構如下:

  • rw_trx_ids:表示在生成 Read View 時,當前活躍的讀寫事務數組。

  • min_trx_id:表示在生成 Read View 時,當前已提交的事務號 + 1,也就是在 rw_trx_ids 中的最小事務號。

  • max_trx_id:表示在生成 Read View 時,當前已分配的事務號 + 1,也就是將要分配給下一個事務的事務號。

  • curr_trx_id:創建 Read View 的當前事務 id。

  • MySQL 會根據以下規則來判斷版本鏈中的哪個版本(記錄)是在事務中可見的:

  • trx_id < min_trx_id,那么該記錄則在當前事務可見,因為修改該版本記錄的事務在當前事務生成 Read View 之前就已經提交。

  • trx_id in (rw_trx_ids),那么該記錄在當前事務不可見,因為需改該版本記錄的事務在當前事務生成 Read View 之前還未提交。

  • trx_id > max_trx_id,那么該記錄在當前事務不可見,因為修改該版本記錄的事務在當前事務生成 Read View 之前還未開啟。

  • trx_id = curr_trx_id,那么該記錄在當前事務可見,因為修改該版本記錄的事務就是當前事務。


我們首先步驟 1 中開啟了一個讀取事務,因為它是一個只讀事務,所以它的事務 id 為 0(以下簡稱事務 0)。緊接著我們在事務 0 中查詢 id 為 1 的記錄。

注意:跟紅色表頭連接在一起的記錄都是在 B+ 樹中的,而通過 roll_ptr 指針連接的記錄都是存在于 undo log 中的。以下的所有版本鏈都是這種形式。

READ UNCOMMITTED

該隔離級別不會使用 MVCC。它只要執行 select,那么就會獲取 B+ 樹上最新的記錄。而不管該記錄的事務是否已經提交。

READ COMMITTED

在 READ COMMITTED 隔離級別下,會使用 MVCC。在開啟一個讀取事務之后,它會在每一個 select 操作之前都生成一個 Read View。

因為步驟 2 中的 select 讀取時,沒有活躍的事務,也就表明所有的事務都是已經提交了的。所以它能讀取到第一條記錄。

執行步驟 3, 開啟一個新的事務,事務 id 為 101(以下檢測事務 101)。

執行步驟 4,它修改了 id 為 1 的記錄,此時版本鏈

執行步驟 5,事務 0 執行了一個 select 操作,事務 0 會生成一個 Read View。

我們根據上面對版本鏈中的記錄可見性規則:

  1. 版本鏈中的第一條記錄,它的 trx_id 不小于 min_trx_id,所以該記錄不可見。

  2. 版本鏈中的第二條記錄,它的 trx_id 小于 min_trx_id,所以該記錄可見。

所以對于此次的查詢,它能獲得的記錄就是:

事務 101 在步驟 5 中執行了一個更新操作,執行步驟 6,提交該事務。

執行步驟 7,我們在事務 0 中執行一次 select 查詢,因為我們的隔離級別是 READ COMMITTED,所以此次查詢也會生成一個 Read View。

然后根據版本鏈可見性規則:

  • 因為沒有活躍的事務,可知所有事務都已經提交,所以 rw_trx_ids 為空。

  • 版本鏈第 1 條記錄,它的 trx_id 小于 min_trx_id,所以此記錄可見。

那么這次的查詢可以得到的記錄。在事務 0 執行完查詢之后,我們又開啟了一個事務 id 為 102 的新事務(以下簡稱事務 102),該事務也對 id 為 1的記錄進行了更新。

步驟 9 中的查詢自行分析。我們直接給出事務 102 執行完兩條更新語句的最終版本鏈

執行步驟 11,根據版本鏈可見性規則,它能獲取到的記錄:

REPEATABLE READ

實際上,REPEATABLE READ 與 READ COMMITTED 的區別只有在生成 Read View 的時機上。

READ COMMITTED 是在每次執行 select 操作時,都會生成一個新的 Read View。而 REPEATABLE READ 只會在第一次執行 select 操作時生成一個 Read View,直到該事務提交之前,所有的 select 操作都是使用第一次生成的 Read View。

我們重新執行一下表中的步驟。

首先,執行到步驟 2,事務 0 開啟了事務之后,并執行一次 select 查詢。此時會生成一個 Read View。該 Read View 的結構如下:

生成的 Read View 將會一直使用,直到事務 0 提交。

所以,盡管后面的開啟了兩個事務,并且對記錄進行修改,使得最終的版本鏈變為如下所示:

但是事務 0 依然只能讀取到最開始的那條記錄。

不管事務 0 在任何時候執行 select * from person where id = 1; 讀取記錄,那么它都只會使用第一次生成的 Read View 在版本鏈中選擇可以讀取的記錄。

SERIALIZABLE

該隔離級別不會使用 MVCC。如果使用的是普通的 select 語句,它會在該語句后面加上 lock in share mode,變為一致性鎖定讀。假設一個事務讀取一條記錄,其他事務對該記錄的更改都會被阻塞。假設一個事務在更改一條記錄,其他事務對該記錄的讀取都會被阻塞。

在該隔離級別下,讀寫操作變為了串行操作。

總結

通過上面的文章,我們可以知道在 READ COMMITTED 和 REPEATABLE READ 隔離等級之下才會使用 MVCC。

但是 READ COMMITTED 和 REPEATABLE READ 使用 MVCC 的方式各不相同:

  • READ COMMITTED 是在每次執行 select 操作時都會生成一次 Read View。

  • REPEATABLE READ 只有在第一次執行 select 操作時才會生成 Read View,后續的 select 操作都將使用第一次生成的 Read View。

而 READ UNCOMMITTED 和 SERIALIZABLE 隔離級別不會使用 MVCC。

它們的讀取操作也不相同:

  • READ UNCOMMITTED 每次執行 select 都會去讀最新的記錄。

  • SERIALIZABLE 每次執行 select 操作都會在該語句后面加上 lock in share mode,使 select 變為一致性鎖定讀,將讀寫進行串行化。

看完上述內容,你們掌握MySQL中的MVCC是怎么樣的的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女