久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

MySQL事務(wù)、隔離級別及MVCC是什么

141次閱讀
沒有評論

共計 9666 個字符,預計需要花費 25 分鐘才能閱讀完成。

自動寫代碼機器人,免費開通

這篇文章主要介紹了 MySQL 事務(wù)、隔離級別及 MVCC 是什么,具有一定借鑒價值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓丸趣 TV 小編帶著大家一起了解一下。

mysql 教程欄目介紹 MySQL 相關(guān)的事務(wù)、隔離級別及 MVCC。

MySQL 系列的第四篇,主要內(nèi)容是事務(wù),包括事務(wù) ACID 特性,隔離級別,臟讀、不可重復讀、幻讀的理解以及多版本并發(fā)控制(MVCC)等內(nèi)容。

事務(wù)(Transaction)能夠保證一組不可分割的原子性操作集合要么都執(zhí)行,要么都不執(zhí)行。在 MySQL 常用的存儲引擎中,InnoDB 是支持事務(wù)的,原生的 MyISAM 引擎則不支持事務(wù)。

在本文中,若未特殊說明,使用的數(shù)據(jù)表及數(shù)據(jù)如下所示:

CREATE TABLE `user` (`id` int(11) DEFAULT NULL, `name` varchar(12) DEFAULT NULL) ENGINE = InnoDB;insert into user values(1, 刺猬 復制代碼 

1. ACID 四大特性

首先需要理解的是事務(wù) ACID 四大特性,即原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability),這也是事務(wù)的四個基本要素。

為了詳細解釋 ACID 特性,在這里先設(shè)想一個場景:我向你轉(zhuǎn)賬 100 元。

假設(shè)這個操作可以分為以下幾步(假設(shè)我和你的賬戶余額均為 100 元):

查詢我的賬戶余額我的賬戶扣款 100 元 100 元開始轉(zhuǎn)移查詢你的賬戶余額你的賬戶到賬 100 元 1.1 原子性(Atomicity)

事務(wù)的原子性是指:一個事務(wù)必須是不可再分割的最小工作單元,一個事務(wù)中的操作要么都成功,要么都失敗,不可能存在只執(zhí)行一個事務(wù)中部分操作的情況。

在上述的轉(zhuǎn)賬場景中,原子性就要求了這五個步驟要么都執(zhí)行,要么都不執(zhí)行,不可能存在我的賬戶扣款 100 元,而你的賬戶 100 元沒有到賬的情況。

1.2 一致性(Consistency)

事務(wù)的一致性是指:數(shù)據(jù)庫總是從一個一致性狀態(tài)轉(zhuǎn)換到另一個一致性狀態(tài),一致性側(cè)重的是數(shù)據(jù)的可見性,數(shù)據(jù)的中間狀態(tài)對外是不可見的。

同時,事務(wù)的一致性要求符合開發(fā)人員定義的約束,如金額大于 0、身高大于 0 等。

在上述的轉(zhuǎn)賬場景中,一致性能夠保證最終執(zhí)行完整個轉(zhuǎn)賬操作后,我賬戶的扣款金額與你賬戶到賬金額是一致的,同時如果我和你的賬戶余額不滿足金額的約束(如小于 0),整個事務(wù)會回滾。

1.3 隔離性(Isolation)

事務(wù)的隔離性是指:在一次狀態(tài)轉(zhuǎn)換過程中不會受到其他狀態(tài)轉(zhuǎn)換的影響。

假設(shè)我和你都有 100 元,我發(fā)起兩次轉(zhuǎn)賬,轉(zhuǎn)賬金額都是 50 元,下面使用偽代碼來表示的操作步驟:

查詢我的賬戶余額 read my 我的賬戶扣款 50 元 my=my-5050 元開始轉(zhuǎn)移查詢你的賬戶余額 read yours 你的賬戶到賬 50 元 yours=yours+50

如果未保證隔離性就可能發(fā)生下面的情況:

時刻第一次轉(zhuǎn)賬第二次轉(zhuǎn)賬我的賬戶余額你的賬戶余額 1read my(100)
my=100yours=1002
read my(100)my=100yours=1003my=my-50=100-50=50
my=50yours=1004read yours(100)my=my-50=100-50=50my=50yours=1005yours=yours+50=100+50=150
my=50yours=1506
read yours(150)my=50yours=1507
yours=yours+50=150+50=200my=50yours=2007endendmy=50yours=200

兩次轉(zhuǎn)賬后,最終的結(jié)果是我的賬戶余額為 50 元,你的賬戶余額為 200 元,這顯然是不對的。

而如果在保證事務(wù)隔離性的情況下,就不會發(fā)生上面的情況,損失的只是一定程度上的一致性。

1.4 持久性(Durability)

事務(wù)的持久性是指:事務(wù)在提交以后,它所做的修改就會被永久保存到數(shù)據(jù)庫。

在上述的轉(zhuǎn)賬場景中,持久性就保證了在轉(zhuǎn)賬成功之后,我的賬戶余額為 0,你的賬戶余額為 200。

2. 自動提交與隱式提交 2.1 自動提交

在 MySQL 中,我們可以通過 begin 或 start transaction 來開啟事務(wù),通過 commit 來關(guān)閉事務(wù),如果 SQL 語句中沒有這兩個命令,默認情況下每一條 SQL 都是一個獨立的事務(wù),在執(zhí)行完成后自動提交。

比如:

update user set name= 重塑 where id=1; 復制代碼 

假設(shè)我只執(zhí)行這一條更新語句,在我關(guān)閉 MySQL 客戶端然后重新打開一個新的客戶端后,可以看到 user 表中的 name 字段值全變成了「重塑」,這也印證了這條更新語句在執(zhí)行后已被自動提交。

自動提交是 MySQL 的一個默認屬性,可以通過 SHOW VARIABLES LIKE autocommit 語句來查看,當它的值為 ON 時,就代表開啟事務(wù)的自動提交。

mysql SHOW VARIABLES LIKE autocommit 
+---------------+-------+| Variable_name | Value |
+---------------+-------+| autocommit | ON |
+---------------+-------+1 row in set (0.00 sec) 復制代碼 

我們可以通過 SET autocommit = OFF 來關(guān)閉事務(wù)的自動提交。

2.2 隱式提交

然而,即便我們已經(jīng)將 autocommit 變量的值改為 OFF 關(guān)閉事務(wù)自動提交了,在執(zhí)行某些 SQL 語句的時候,MySQL 還是會將事務(wù)自動提交掉,這被稱為隱式提交。

會觸發(fā)隱式提交的 SQL 語句有:

DDL(Data definition language,數(shù)據(jù)定義語言),如 create, drop, alter, truncate 修改 MySQL 自帶表數(shù)據(jù)的語句,如 create/drop user, grant, set password 在一個事務(wù)中,開啟一個新的事務(wù),會隱式提交上一個事務(wù),如:時刻事務(wù) A 事務(wù) B1begin;
2update user set name= 重塑 where id=1;
3
select name from user where id=1;(N1)4begin;
5
select name from user where id=1;(N2)

在事務(wù) B 中有兩個查詢語句 N1 和 N2,執(zhí)行的結(jié)果是 N1= 刺猬,N2= 重塑,由此可以證明。

其他還有一些管理語句就不一一舉例了,可自行百度。3. 隔離級別

事務(wù)的隔離級別規(guī)定了一個事務(wù)中所做的修改,在事務(wù)內(nèi)和事務(wù)間的可見性。較低級別的隔離通常可以執(zhí)行更高的并發(fā),系統(tǒng)開銷也更低。

在 SQL 標準中定義了四種事務(wù)的隔離級別,分別是讀未提交(Read Uncommitted)、讀已提交(Read Committed)、可重復讀(Repeatable Read)、可串行化(Serializable)。

為了詳細解釋這四種隔離級別及它們各自發(fā)生的現(xiàn)象,假設(shè)有兩個事務(wù)即將執(zhí)行,執(zhí)行內(nèi)容如下表:

時刻事務(wù) A 事務(wù) B1begin;
2
begin;3
update user set name= 重塑 where id=1;4select name from user where id=1;(N1)
5
commit;6select name from user where id=1;(N2)
7commit;
8select name from user where id=1;(N3)

在事務(wù) A 和事務(wù) B 執(zhí)行的過程中,有三處查詢 N1,N2,N3,在每個隔離級別下,它們值的情況是不同的,下面分別討論。

3.1 讀未提交(Read Uncommitted)

在讀未提交的隔離級別下,事務(wù)中的修改,即便沒有提交,對其他事務(wù)也都是可見的。

在上述場景中,若數(shù)據(jù)庫的隔離級別為讀未提交,由于事務(wù) A 可以讀取未提交事務(wù) B 修改后的數(shù)據(jù),即時刻 3 中事務(wù) B 的修改對事務(wù) A 可見,所以 N1= 重塑,N2= 重塑,N3= 重塑。

3.2 讀已提交(Read Committed)

在讀已提交的隔離級別下,事務(wù)中的修改只有在提交之后,才會對其他事務(wù)可見。

在上述場景中,若數(shù)據(jù)庫的隔離級別為讀已提交,由于事務(wù) A 只能讀取事務(wù) B 提交后的數(shù)據(jù),即時刻 3 中事務(wù) B 的修改對事務(wù) A 不可見,N2 處的查詢在事務(wù) B 提交之后,故對事務(wù) A 可見。所以 N1= 刺猬,N2= 重塑,N3= 重塑。

3.3 可重復讀(Repeatable Read)

可重復讀是 MySQL 的默認事務(wù)隔離級別。在可重復讀的隔離級別下,一個事務(wù)中多次查詢相同的記錄,結(jié)果總是一致的。

在上述場景中,若數(shù)據(jù)庫的隔離級別為可重復讀,由于查詢 N1 和 N2 在一個事務(wù)中,所以它們的值都是「刺猬」,而 N3 是在事務(wù) A 提交以后再進行的查詢,對事務(wù) B 的修改是可見的,所以 N3= 重塑。

3.4 可串行化(Serializable)

在可串行化的隔離級別下,事務(wù)都是串行執(zhí)行的,讀會加讀鎖,寫會加寫鎖,事務(wù)不會并發(fā)執(zhí)行,所以也就不會發(fā)生異常情況。

在上述場景中,若數(shù)據(jù)庫的隔離級別為可串行化,首先開啟事務(wù) A,在開啟事務(wù) B 時被阻塞,直到事務(wù) A 提交之后才會開啟事務(wù) B,所以 N1= 刺猬,N2= 刺猬。而 N3 處的查詢會在事務(wù) B 提交之后才執(zhí)行(事務(wù) B 先被阻塞,執(zhí)行順序在 N3 查詢語句之前),所以 N3= 重塑。

4. 隔離級別導致的問題

在不同的事務(wù)隔離級別中,如果遇到事務(wù)并發(fā)執(zhí)行,就會出現(xiàn)很多問題,如臟讀(Dirty Read)、不可重復讀(Non-Repeatable Read)、幻讀(Phantom Read)等,下面就分別用不同的例子來詳細說明這些問題。

4.1 臟讀(Dirty Read)

臟讀(Dirty Read)是指一個事務(wù)可以讀取另一個未提交事務(wù)修改的數(shù)據(jù)。

看下面的案例,假設(shè)隔離級別為讀未提交:

時刻事務(wù) A 事務(wù) B1begin;
2
begin;3
update user set name= 重塑 where id=1;4select name from user where id=1;(N1)
5
rollback;6select name from user where id=1;(N2)
7commit;

在讀未提交的隔離級別下,N1 的值是「重塑」,由于事務(wù) B 的回滾,N2 的值是「刺猬」。這里在 N1 處就發(fā)生了臟讀,顯然 N1 處的查詢結(jié)果是一個臟數(shù)據(jù),會對正常業(yè)務(wù)產(chǎn)生影響。

臟讀會發(fā)生在讀未提交的隔離級別中。

4.2 不可重復讀(Non-Repeatable Read)

不可重復讀(Non-Repeatable Read)是指,兩次執(zhí)行相同的查詢可能會得到不一樣的結(jié)果。

繼續(xù)使用介紹隔離級別時的 AB 事務(wù)案例,同時假設(shè)隔離級別為讀已提交:

時刻事務(wù) A 事務(wù) B1begin;
2
begin;3
update user set name= 重塑 where id=1;4select name from user where id=1;(N1)
5
commit;6select name from user where id=1;(N2)
7commit;
8select name from user where id=1;(N3)

在讀已提交的隔離級別下,事務(wù)可以讀取到其他事務(wù)提交的數(shù)據(jù)。在上述案例中結(jié)果是 N1= 刺猬,N2= 重塑,N3= 重塑,在事務(wù) A 中,有兩次相同的查詢 N1 和 N2,但是這兩次查詢的結(jié)果并不相同,這就發(fā)生了不可重復讀。

不可重復讀會發(fā)生在讀未提交、讀已提交的隔離級別中。

4.3 幻讀(Phantom Read)

幻讀(Phantom Read)是指,一個事務(wù)在讀取某個范圍內(nèi)記錄時,另外一個事務(wù)在該范圍內(nèi)插入一條新記錄,當之前的事務(wù)再次讀取這個范圍的記錄時,會讀到這條新記錄。

看下面的案例,假設(shè)此時隔離級別為可重復讀:

時刻事務(wù) A 事務(wù) B1begin;
2select name from user;(N1)
3
begin;4
insert into user values(2, 五條人 5
commit;6select name from user;(N2)
7select name from user for update;(N3)
8commit;

事務(wù) A 有三次查詢,在 N1 和 N2 之間,事務(wù) B 執(zhí)行了一條 insert 語句并提交,N3 處的查詢使用的是 for update。

N1 處的結(jié)果很顯然只有「刺猬」,N2 處的結(jié)果由于事務(wù) A 開啟在事務(wù) B 之前,所以也是「刺猬」,而 N3 處的結(jié)果理論上在可重復讀的隔離級別中也應(yīng)該只有「刺猬」,但實際上 N2 的結(jié)果是「刺猬」和「五條人」,這就發(fā)生了幻讀。

這就很奇怪了,不是說可重復讀的隔離級別能夠保證一個事務(wù)中多次查詢相同的記錄,結(jié)果總是一致的嗎?這種結(jié)果并不滿足可重復讀的定義。

事實上,在可重復讀的隔離級別下,如果使用的是當前讀,那么就可能發(fā)生幻讀現(xiàn)象。

當前讀和快照讀會在下文中介紹事務(wù)的實現(xiàn)原理及 MVCC 時討論,這里先給一個結(jié)論。

幻讀會發(fā)生在讀未提交、讀已提交、可重復讀的隔離級別中。

這里需要額外注意的是:幻讀和不可重復讀都是說在一個事務(wù)中的同一個查詢語句結(jié)果不同,但幻讀更側(cè)重于查詢到其他事務(wù)新插入的數(shù)據(jù)(insert)或其他事務(wù)刪除的數(shù)據(jù)(delete),而不可重復讀的范圍更廣,只要結(jié)果不同就可以認為是不可重復讀,但一般我們認為不可重復讀更側(cè)重于其他事務(wù)對數(shù)據(jù)的更新(update)。

4.4 小結(jié)

通過上面的描述,我們已經(jīng)知道四種隔離級別的概念以及它們分別會遇到的問題,事務(wù)的隔離級別越高,隔離性就越強,所遇到的問題也就越少。但同時,隔離級別越高,并發(fā)能力就越弱。

下表是對隔離級別的概念不同隔離級別會發(fā)生的問題情況的小結(jié):

隔離級別臟讀不可重復讀幻讀概念讀已提交√√√事務(wù)中的修改,即便沒有提交,對其他事務(wù)也都是可見的讀未提交
√√事務(wù)中的修改只有在提交之后,才會對其他事務(wù)可見可重復讀

√一個事務(wù)中多次查詢相同的記錄,結(jié)果總是一致的可串行化

事務(wù)都是串行執(zhí)行的,讀會加讀鎖,寫會加寫鎖 5. MVCC

MVCC(Multi-Version Concurrency Control)即多版本并發(fā)控制,這是 MySQL 為了提高數(shù)據(jù)庫并發(fā)性能而實現(xiàn)的。它可以在并發(fā)讀寫數(shù)據(jù)庫時,保證不同事務(wù)的讀 - 寫操作并發(fā)執(zhí)行,同時也能解決臟讀、不可重復讀、幻讀等事務(wù)隔離問題。

在前文討論幻讀的時候提到過當前讀的概念,正是由于當前讀,才會在可重復讀的隔離級別下也會發(fā)生幻讀的情況。

在解釋可重復讀隔離級別下發(fā)生幻讀的原因之前,首先介紹 MVCC 的實現(xiàn)原理。

5.1 MVCC 的實現(xiàn)原理

首先我們需要知道,InnoDB 的數(shù)據(jù)頁中每一行的數(shù)據(jù)是有隱藏字段的:

DB_ROW_ID: 隱式主鍵,若表結(jié)構(gòu)中未定義主鍵,InnoDB 會自動生成該字段作為表的主鍵 DB_TRX_ID: 事務(wù) ID,代表修改此行記錄的最后一次事務(wù) IDDB_ROLL_PTR: 回滾指針,指向此行記錄的上一個版本(上一個事務(wù) ID 對應(yīng)的記錄)

每一條修改語句都會相應(yīng)地記錄一條回滾語句(undo log),如果把每一條回滾語句視為一條數(shù)據(jù)表中的記錄,那么通過事務(wù) ID 和回滾指針就可以將對同一行的修改記錄看作一個鏈表,鏈表上的每一個節(jié)點就是一個快照版本,這就是 MVCC 中多版本的意思。

舉個例子,假設(shè)對 user 表中唯一的一行「刺猬」進行多次修改。

update user set name= 重塑 where id=1;update user set name= 木馬 where id=1;update user set name= 達達 where id=1; 復制代碼 

那么這條記錄的版本鏈就是:

MySQL 事務(wù)、隔離級別及 MVCC 是什么

在這個版本鏈中,頭結(jié)點就是當前記錄的最新版本。DB_TRX_ID 事務(wù) ID 字段是非常重要的屬性,先 Mark 一下。

除此之外,在讀已提交(RC,Read Committed)和可重復讀(RR,Repeatable Read)的隔離級別中,事務(wù)在啟動的時候會創(chuàng)建一個讀視圖(Read View),用它來記錄當前系統(tǒng)的活躍事務(wù)信息,通過讀視圖來進行本事務(wù)之間的可見性判斷。

在讀視圖中有兩個重要的屬性:

當前事務(wù) ID:表示生成讀視圖的事務(wù)的事務(wù) ID 事務(wù) ID 列表:表示在生成讀視圖時,當前系統(tǒng)中活躍著的事務(wù) ID 列表最小事務(wù) ID:表示在生成讀視圖時,當前系統(tǒng)中活躍著的最小事務(wù) ID 下一個事務(wù) ID:表示在生成讀視圖時,系統(tǒng)應(yīng)該分配給下一個事務(wù)的事務(wù) ID

需要注意下一個事務(wù) I 的值,并不是事務(wù) ID 列表中的最大值 +1,而是當前系統(tǒng)中已存在過的事務(wù)的最大值 +1。例如當前數(shù)據(jù)庫中活躍的事務(wù)有 (1,2),此時事務(wù) 2 提交,同時又開啟了新事務(wù),在生成的讀視圖中,下一個事務(wù) ID 的值為 3。

我們通過將版本鏈與讀視圖兩者結(jié)合起來,來進行并發(fā)事務(wù)間可見性的判斷,判斷規(guī)則如下(假設(shè)現(xiàn)在要判斷事務(wù) A 是否可以訪問到事務(wù) B 的修改記錄):

若事務(wù) B 的當前事務(wù) ID 小于事務(wù) A 的最小事務(wù) ID 的值,代表事務(wù) B 是在事務(wù) A 生成讀視圖之前就已經(jīng)提交了的,所以事務(wù) B 對于事務(wù) A 來說是可見的。若事務(wù) B 的當前事務(wù) ID 大于或等于事務(wù) A 下一個事務(wù) ID 的值,代表事務(wù) B 是在事務(wù) A 生成讀視圖之后才開啟,所以事務(wù) B 對于事務(wù) A 來說是不可見的。若事務(wù) B 的當前事務(wù) ID 在事務(wù) A 的最小事務(wù) ID 和下一個事務(wù) ID 之間(左閉右開,[最小事務(wù) ID, 下一個事務(wù) ID)),需要分兩種情況討論:若事務(wù) B 的當前事務(wù) ID 在事務(wù) A 的事務(wù) ID 列表中,代表創(chuàng)建事務(wù) A 時事務(wù) B 還是活躍的,未提交,所以事務(wù) B 對于事務(wù) A 來說是不可見的。若事務(wù) B 的當前事務(wù) ID 不在事務(wù) A 的事務(wù) ID 列表中,代表創(chuàng)建事務(wù) A 時事務(wù) B 已經(jīng)提交,所以事務(wù) B 對于事務(wù) A 來說是可見的。

如果事務(wù) B 對于事務(wù) A 來說是不可見的,就需要順著修改記錄的版本鏈,從回滾指針開始往前遍歷,直到找到第一個對于事務(wù) A 來說是可見的事務(wù) ID,或者遍歷完版本鏈也未找到(表示這條記錄對事務(wù) A 不可見)。

這就是 MVCC 的實現(xiàn)原理。

5.2 讀視圖的創(chuàng)建時機

這里需要注意的是讀視圖的創(chuàng)建時機,在上面的論述中我們已經(jīng)知道事務(wù)在啟動時會創(chuàng)建一個讀視圖(Read View),而開啟一個事務(wù)有兩種方式,一是 begin/start transaction,二是 start transaction with consistent snapshot,通過這兩種方式開啟事務(wù),創(chuàng)建讀視圖的時機也是不同的:

如果是以 begin/start transaction 方式開啟事務(wù),讀視圖會在執(zhí)行第一個快照讀語句時創(chuàng)建如果以 start transaction with consistent snapshot 方式開啟事務(wù),同時便會創(chuàng)建讀視圖 5.3 MVCC 的運行過程

為了詳細說明 MVCC 的運行過程,下面舉個例子,假設(shè)當前存在有兩個事務(wù)(事務(wù)隔離級別為 MySQL 默認的可重復讀):

這里需要注意的是事務(wù)的啟動時機,在上面的論述中我們已經(jīng)知道事務(wù)在啟動時會創(chuàng)建一個讀視圖(Read View),而開啟一個事務(wù)有兩種方式,一是 begin/start transaction,二是 start transaction with consistent snapshot,通過這兩種方式開啟事務(wù),創(chuàng)建讀視圖的時機也是不同的:

如果是以 begin/start transaction 方式開啟事務(wù),讀視圖會在執(zhí)行第一個快照讀語句時創(chuàng)建如果以 start transaction with consistent snapshot 方式開啟事務(wù),同時便會創(chuàng)建讀視圖時刻事務(wù) A 事務(wù) B1start transaction with consistent snapshot;
2
start transaction with consistent snapshot;3
update user set name= 重塑 where id=1;4select name from user where id=1;(N1)
5
commit;6select name from user where id=1;(N2)
7commit;

然后根據(jù)上面所描述的版本鏈以及兩個事務(wù)開啟時的讀視圖來分析 MVCC 的運行過程。

MySQL 事務(wù)、隔離級別及 MVCC 是什么

上圖是兩個事務(wù)開啟時的讀視圖,而當事務(wù) B 的更新語句執(zhí)行之后,id= 1 行的版本鏈如下所示。

MySQL 事務(wù)、隔離級別及 MVCC 是什么

先來看 N1 處的查詢語句,事務(wù) B 的當前事務(wù) ID=2,其值等于事務(wù) A 的下一個事務(wù) ID,所以按照上文中所論述的可見性判斷,事務(wù) B 對于事務(wù) A 來說是不可見的,需要循著當前行的版本鏈網(wǎng)上檢索。

于是循著版本鏈來到 DB_TRX_ID= 1 事務(wù) ID= 1 的歷史版本,恰巧等于事務(wù) A 的事務(wù) ID 值,也就是事務(wù) A 開啟時該行的版本,此版本對于事務(wù) A 來說當然是可見的,所以讀取到了 id= 1 行的 name= 刺猬,即最終 N1= 刺猬。

再來看 N2 處的查詢語句,此時事務(wù) B 已提交,版本鏈還是如上圖所示,由于當前版本的事務(wù) ID 等于事務(wù) A 讀視圖中的下一個事務(wù) ID,所以當前版本的記錄對于事務(wù) A 來說是不可見的,所以同樣 N2= 刺猬。

這里需要注意的是,若例子中事務(wù) A 的時刻 4 語句變更為對該行的更新語句,那么事務(wù) A 便會等待事務(wù) B 提交之后再執(zhí)行更新語句,這是因為事務(wù) B 未提交,即事務(wù) B 對于 id= 1 行的寫鎖未釋放,而事務(wù) A 也要更新該行,必須是更新當前的最新版本(當前讀)才可以,所以事務(wù) A 就被阻塞了,必須等待事務(wù) B 對該行的寫鎖釋放,才會繼續(xù)執(zhí)行更新語句。

5.4 RC 與 RR 生成讀視圖的時機對比

上面所討論的 MVCC 運行過程都是針對可重復讀(RR, Repeatable Read)隔離級別的,如果是讀已提交(RC, Read Committed)級別呢?

上文中已經(jīng)討論過讀已提交隔離級別中關(guān)于不可重復讀的情況了,這里就不再舉例,直接給出結(jié)論就可以了。

可重復讀(RR, Repeatable Read)隔離級別下生成讀視圖(Read View)的時機是開啟事務(wù)的時候讀已提交(RC, Read Committed)隔離級別下生成讀視圖(Read View)的時機是每一條語句執(zhí)行前

對于上文中描述 MVCC 執(zhí)行過程中的例子,如果隔離級別是讀已提交(RC, Read Committed):

N1 處的查詢語句,由于事務(wù) B 還未提交,事務(wù) A 可見的版本依舊是事務(wù) ID= 1 的版本,所以 N1= 刺猬 N2 處的查詢語句,事務(wù) B 已提交,N2 處查詢語句執(zhí)行時也會生成讀視圖,其當前事務(wù) ID=3,而在該記錄的版本鏈中,當前版本的事務(wù) ID DB_TRX_ID=2,在 N2 查詢語句事務(wù) ID 之前,是可見的,所以 N2= 重塑 5.5 當前讀與快照讀當前讀:讀取記錄的最新版本快照讀:讀取記錄時會根據(jù)一定規(guī)則讀取事務(wù)可見版本的記錄 5.6 可重復讀發(fā)生幻讀的原因

在理解了 MVCC 之后,我們再來看在可重復讀隔離級別下發(fā)生幻讀的原因。上文中說到正是由于當前讀,才會在可重復讀的隔離級別下發(fā)生幻讀的情況,首先來回顧一下例子。

時刻事務(wù) A 事務(wù) B1begin;
2select name from user;(N1)
3
begin;4
insert into user values(2, 五條人 5
commit;6select name from user;(N2)
7select name from user for update;(N3)
8commit;

N1,N2 處的查詢想必已經(jīng)十分明確都是「刺猬」了。而在 N3 處所使用的查詢語句是 for update,使用它進行查詢就會對目標記錄添加一把「行級鎖」,行級鎖的意義以后再說,現(xiàn)在只需要知道 for update 能夠鎖住目標記錄就可以了。

加鎖自然是防止別人修改,那么理所當然,鎖住的當然也就是記錄的最新版本了。所以,在使用 for update 進行查詢的時候,會使用當前讀,讀到目標記錄的最新版本,所以在 N3 處的查詢語句就會把事務(wù) B 中本對于事務(wù) A 來說不可見的記錄也查詢出來,也就發(fā)生了幻讀。

使用當前讀的語句有:

select … for updateselect … lock in share mode(共享讀鎖)update …insert …delete …

感謝你能夠認真閱讀完這篇文章,希望丸趣 TV 小編分享 MySQL 事務(wù)、隔離級別及 MVCC 是什么內(nèi)容對大家有幫助,同時也希望大家多多支持丸趣 TV,關(guān)注丸趣 TV 行業(yè)資訊頻道,遇到問題就找丸趣 TV,詳細的解決方法等著你來學習!

向 AI 問一下細節(jié)

丸趣 TV 網(wǎng) – 提供最優(yōu)質(zhì)的資源集合!

正文完
 
丸趣
版權(quán)聲明:本站原創(chuàng)文章,由 丸趣 2023-12-18發(fā)表,共計9666字。
轉(zhuǎn)載說明:除特殊說明外本站除技術(shù)相關(guān)以外文章皆由網(wǎng)絡(luò)搜集發(fā)布,轉(zhuǎn)載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 叶城县| 北宁市| 德化县| 安多县| 宜川县| 大竹县| 即墨市| 古田县| 宁波市| 湘潭县| 天峨县| 专栏| 巩义市| 武胜县| 通州区| 施秉县| 四子王旗| 连城县| 贺州市| 衡水市| 调兵山市| 大厂| 祁东县| 桦南县| 汽车| 喜德县| 安泽县| 漳浦县| 股票| 怀宁县| 资中县| 贡山| 土默特右旗| 固安县| 昂仁县| 冷水江市| 西安市| 漳平市| 丹棱县| 武冈市| 迭部县|