亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

前言

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

這種沒有靈魂的操作,對(duì)于很多初學(xué)者來說也許已經(jīng)是家常便飯了。但是對(duì)于一些已經(jīng)有開發(fā)經(jīng)驗(yàn)的人來說,這是遠(yuǎn)遠(yuǎn)不夠的。你必須要學(xué)習(xí)很多數(shù)據(jù)庫相關(guān)的知識(shí),而這一篇就是徹底來剖析 MySQL 中的 MVCC 是如何實(shí)現(xiàn)的。看完這篇文章,你就可以知道各種隔離級(jí)別之下,MVCC 的作用是什么?MVCC 在什么時(shí)候會(huì)使用?怎么使用?

示例表

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;
復(fù)制代碼
insert into person values (null, '1351111111', 'any', 20, '蜀');
insert into person values (null, '1351111112', 'bat', 21, '吳');
復(fù)制代碼

id phone name age country 1 1351111111 any 20 蜀 2 1351111112 bat 21 吳

MVCC

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

在數(shù)據(jù)庫中的每一條記錄實(shí)際都會(huì)存在三個(gè)隱藏列:

  • DB_TRX_ID:該列表示此記錄的事務(wù) ID
  • DB_ROLL_PTR:該列表示一個(gè)指向回滾段的指針,實(shí)際就是指向該記錄的一個(gè)版本鏈
  • DB_ROW_ID:記錄的 ID,如果有指定主鍵,那么該值就是主鍵。如果沒有主鍵,那么就會(huì)使用定義的第一個(gè)唯一索引。如果沒有唯一索引,那么就會(huì)默認(rèn)生成一個(gè)值。
start transaction;
update person set age = 22 where id = 1;
update person set name = 'out' where id = 1;
commit;
復(fù)制代碼

當(dāng)執(zhí)行完上面兩條語句之后,但是還沒有提交事務(wù)之前,它的版本鏈如下圖所示:

MySQL 中你必須要懂的 MVCC

 

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

在事務(wù)中,只有執(zhí)行插入、更新、刪除操作時(shí)才會(huì)分配到一個(gè)事務(wù) id。如果事務(wù)只是一個(gè)單純的讀取事務(wù),那么它的事務(wù) id 就是默認(rèn)的 0。

Read View 的結(jié)構(gòu)如下:

  • rw_trx_ids:表示在生成 Read View 時(shí),當(dāng)前活躍的讀寫事務(wù)數(shù)組。
  • min_trx_id:表示在生成 Read View 時(shí),當(dāng)前已提交的事務(wù)號(hào) + 1,也就是在 rw_trx_ids 中的最小事務(wù)號(hào)。
  • max_trx_id:表示在生成 Read View 時(shí),當(dāng)前已分配的事務(wù)號(hào) + 1,也就是將要分配給下一個(gè)事務(wù)的事務(wù)號(hào)。
  • curr_trx_id:創(chuàng)建 Read View 的當(dāng)前事務(wù) id。
MySQL 中你必須要懂的 MVCC

 

MySQL 會(huì)根據(jù)以下規(guī)則來判斷版本鏈中的哪個(gè)版本(記錄)是在事務(wù)中可見的:

  • trx_id < min_trx_id,那么該記錄則在當(dāng)前事務(wù)可見,因?yàn)樾薷脑摪姹居涗浀氖聞?wù)在當(dāng)前事務(wù)生成 Read View 之前就已經(jīng)提交。
  • trx_id in (rw_trx_ids),那么該記錄在當(dāng)前事務(wù)不可見,因?yàn)樾韪脑摪姹居涗浀氖聞?wù)在當(dāng)前事務(wù)生成 Read View 之前還未提交。
  • trx_id > max_trx_id,那么該記錄在當(dāng)前事務(wù)不可見,因?yàn)樾薷脑摪姹居涗浀氖聞?wù)在當(dāng)前事務(wù)生成 Read View 之前還未開啟。
  • trx_id = curr_trx_id,那么該記錄在當(dāng)前事務(wù)可見,因?yàn)樾薷脑摪姹居涗浀氖聞?wù)就是當(dāng)前事務(wù)。

例如:

MySQL 中你必須要懂的 MVCC

 

我們首先步驟 1 中開啟了一個(gè)讀取事務(wù),因?yàn)樗且粋€(gè)只讀事務(wù),所以它的事務(wù) id 為 0(以下簡(jiǎn)稱事務(wù) 0)。緊接著我們?cè)谑聞?wù) 0 中查詢 id 為 1 的記錄。此時(shí),版本鏈如下:

MySQL 中你必須要懂的 MVCC

 

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

READ UNCOMMITTED

該隔離級(jí)別不會(huì)使用 MVCC。它只要執(zhí)行 select,那么就會(huì)獲取 B+ 樹上最新的記錄。而不管該記錄的事務(wù)是否已經(jīng)提交。

READ COMMITTED

在 READ COMMITTED 隔離級(jí)別下,會(huì)使用 MVCC。在開啟一個(gè)讀取事務(wù)之后,它會(huì)在每一個(gè) select 操作之前都生成一個(gè) Read View。

因?yàn)椴襟E 2 中的 select 讀取時(shí),沒有活躍的事務(wù),也就表明所有的事務(wù)都是已經(jīng)提交了的。所以它能讀取到第一條記錄。

執(zhí)行步驟 3, 開啟一個(gè)新的事務(wù),事務(wù) id 為 101(以下檢測(cè)事務(wù) 101)。

執(zhí)行步驟 4,它修改了 id 為 1 的記錄,此時(shí)版本鏈將會(huì)變?yōu)槿缦拢?/p>MySQL 中你必須要懂的 MVCC

 

執(zhí)行步驟 5,事務(wù) 0 執(zhí)行了一個(gè) select 操作,事務(wù) 0 會(huì)生成一個(gè) Read View。Read View 的值如下:

MySQL 中你必須要懂的 MVCC

 

我們根據(jù)上面對(duì)版本鏈中的記錄可見性規(guī)則:

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

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

MySQL 中你必須要懂的 MVCC

 

事務(wù) 101 在步驟 5 中執(zhí)行了一個(gè)更新操作,執(zhí)行步驟 6,提交該事務(wù)之后,版本鏈如下:

MySQL 中你必須要懂的 MVCC

 

執(zhí)行步驟 7,我們?cè)谑聞?wù) 0 中執(zhí)行一次 select 查詢,因?yàn)槲覀兊母綦x級(jí)別是 READ COMMITTED,所以此次查詢也會(huì)生成一個(gè) Read View。該 Read View 的值如下:

MySQL 中你必須要懂的 MVCC

 

然后根據(jù)版本鏈可見性規(guī)則:

  • 因?yàn)闆]有活躍的事務(wù),可知所有事務(wù)都已經(jīng)提交,所以 rw_trx_ids 為空。
  • 版本鏈第 1 條記錄,它的 trx_id 小于 min_trx_id,所以此記錄可見。

那么這次的查詢可以得到的記錄如下所示:

MySQL 中你必須要懂的 MVCC

 

在事務(wù) 0 執(zhí)行完查詢之后,我們又開啟了一個(gè)事務(wù) id 為 102 的新事務(wù)(以下簡(jiǎn)稱事務(wù) 102),該事務(wù)也對(duì) id 為 1的記錄進(jìn)行了更新。

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

MySQL 中你必須要懂的 MVCC

 

執(zhí)行步驟 11,根據(jù)版本鏈可見性規(guī)則,它能獲取到的記錄:

MySQL 中你必須要懂的 MVCC

 

REPEATABLE READ

實(shí)際上,REPEATABLE READ 與 READ COMMITTED 的區(qū)別只有在生成 Read View 的時(shí)機(jī)上。

READ COMMITTED 是在每次執(zhí)行 select 操作時(shí),都會(huì)生成一個(gè)新的 Read View。而 REPEATABLE READ 只會(huì)在第一次執(zhí)行 select 操作時(shí)生成一個(gè) Read View,直到該事務(wù)提交之前,所有的 select 操作都是使用第一次生成的 Read View。

我們重新執(zhí)行一下表中的步驟。

首先,執(zhí)行到步驟 2,事務(wù) 0 開啟了事務(wù)之后,并執(zhí)行一次 select 查詢。此時(shí)會(huì)生成一個(gè) Read View。該 Read View 的結(jié)構(gòu)如下:

MySQL 中你必須要懂的 MVCC

 

生成的 Read View 將會(huì)一直使用,直到事務(wù) 0 提交。

所以,盡管后面的開啟了兩個(gè)事務(wù),并且對(duì)記錄進(jìn)行修改,使得最終的版本鏈變?yōu)槿缦滤荆?/p>MySQL 中你必須要懂的 MVCC

 

但是事務(wù) 0 依然只能讀取到最開始的那條記錄,也就是:

MySQL 中你必須要懂的 MVCC

 

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

SERIALIZABLE

該隔離級(jí)別不會(huì)使用 MVCC。如果使用的是普通的 select 語句,它會(huì)在該語句后面加上 lock in share mode,變?yōu)橐恢滦枣i定讀。假設(shè)一個(gè)事務(wù)讀取一條記錄,其他事務(wù)對(duì)該記錄的更改都會(huì)被阻塞。假設(shè)一個(gè)事務(wù)在更改一條記錄,其他事務(wù)對(duì)該記錄的讀取都會(huì)被阻塞。

在該隔離級(jí)別下,讀寫操作變?yōu)榱舜胁僮鳌?/p>

總結(jié)

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

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

  • READ COMMITTED 是在每次執(zhí)行 select 操作時(shí)都會(huì)生成一次 Read View。
  • REPEATABLE READ 只有在第一次執(zhí)行 select 操作時(shí)才會(huì)生成 Read View,后續(xù)的 select 操作都將使用第一次生成的 Read View。

而 READ UNCOMMITTED 和 SERIALIZABLE 隔離級(jí)別不會(huì)使用 MVCC。

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

  • READ UNCOMMITTED 每次執(zhí)行 select 都會(huì)去讀最新的記錄。
  • SERIALIZABLE 每次執(zhí)行 select 操作都會(huì)在該語句后面加上 lock in share mode,使 select 變?yōu)橐恢滦枣i定讀,將讀寫進(jìn)行串行化。


原文鏈接:https://juejin.im/post/5eeafc15e51d4573fa7d5824

分享到:
標(biāo)簽:MySQL MVCC
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定