一抚岗、事務(wù)及其特性
首先看看什么是事務(wù)?事務(wù)具有哪些特性哪怔?關(guān)于事務(wù)宣蔚,上大學(xué)的時(shí)候,你應(yīng)該有接觸過(guò)相關(guān)的課程认境。簡(jiǎn)單來(lái)說(shuō)胚委,事務(wù)是指作為單個(gè)邏輯工作單元執(zhí)行的一系列操作,這些操作要么全做叉信,要么全不做亩冬,是一個(gè)不可分割的工作單元。
一個(gè)邏輯工作單元要成為事務(wù)硼身,在關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng)中硅急,必須滿足 4 個(gè)特性,即所謂的 ACID:原子性佳遂、一致性铜秆、隔離性和持久性。
一致性:事務(wù)完成之后讶迁,事務(wù)所做的修改進(jìn)行持久化保存连茧,不會(huì)丟失。
原子性:事務(wù)的所有操作巍糯,要么全部完成啸驯,要么全部不完成,不會(huì)結(jié)束在某個(gè)中間環(huán)節(jié)祟峦。
持久性:事務(wù)開(kāi)始之前和事務(wù)結(jié)束之后罚斗,數(shù)據(jù)庫(kù)的完整性限制未被破壞。
隔離性:當(dāng)多個(gè)事務(wù)并發(fā)訪問(wèn)數(shù)據(jù)庫(kù)中的同一數(shù)據(jù)時(shí)宅楞,所表現(xiàn)出來(lái)的相互關(guān)系针姿。
ACID 及它們之間的關(guān)系如下圖所示袱吆,比如 4 個(gè)特性中有 3 個(gè)與 WAL 有關(guān)系,都需要通過(guò) Redo距淫、Undo 日志來(lái)保證等绞绒。
1.一致性
首先來(lái)看一致性,一致性其實(shí)包括兩部分內(nèi)容榕暇,分別是約束一致性和數(shù)據(jù)一致性蓬衡。
約束一致性:數(shù)據(jù)庫(kù)中創(chuàng)建表結(jié)構(gòu)時(shí)所指定的外鍵、Check彤枢、唯一索引等約束狰晚。可惜在 MySQL 中缴啡,是不支持 Check 的壁晒,只支持另外兩種,所以約束一致性就非常容易理解了业栅。
數(shù)據(jù)一致性:是一個(gè)綜合性的規(guī)定秒咐,或者說(shuō)是一個(gè)把握全局的規(guī)定。因?yàn)樗怯稍有允礁洹⒊志眯浴⒏綦x性共同保證的結(jié)果固蚤,而不是單單依賴于某一種技術(shù)娘汞。
2.原子性
接下來(lái)看原子性,原子性就是前面提到的兩個(gè)“要么”夕玩,即要么改了你弦,要么沒(méi)改。也就是說(shuō)用戶感受不到一個(gè)正在改的狀態(tài)燎孟。MySQL 是通過(guò) WAL(Write Ahead Log)技術(shù)來(lái)實(shí)現(xiàn)這種效果的禽作。
舉例來(lái)講,如果事務(wù)提交了揩页,那改了的數(shù)據(jù)就生效了旷偿,如果此時(shí) Buffer Pool 的臟頁(yè)沒(méi)有刷盤,需要使用 Redo 日志恢復(fù)出來(lái)的數(shù)據(jù)爆侣。而如果事務(wù)沒(méi)有提交萍程,且 Buffer Pool 的臟頁(yè)被刷盤了,需要通過(guò) Undo 來(lái)實(shí)現(xiàn)了兔仰,Undo 又是通過(guò) Redo 來(lái)保證的茫负,所以最終原子性的保證還是靠 Redo 的 WAL 機(jī)制實(shí)現(xiàn)的。
3.持久性
所謂持久性乎赴,就是指一個(gè)事務(wù)一旦提交忍法,它對(duì)數(shù)據(jù)庫(kù)中數(shù)據(jù)的改變就應(yīng)該是永久性的潮尝,接下來(lái)的操作或故障不應(yīng)該對(duì)其有任何影響。前面已經(jīng)講到饿序,事務(wù)的原子性可以保證一個(gè)事務(wù)要么全執(zhí)行勉失,要么全不執(zhí)行的特性,這可以從邏輯上保證用戶看不到中間的狀態(tài)嗤堰。一旦事務(wù)提交戴质,通過(guò)原子性,即便是遇到宕機(jī)踢匣,也可以從邏輯上將數(shù)據(jù)找回來(lái)后再次寫入物理存儲(chǔ)空間告匠,這樣就從邏輯和物理兩個(gè)方面保證了數(shù)據(jù)不會(huì)丟失,即保證了數(shù)據(jù)庫(kù)的持久性离唬。
4.隔離性
所謂隔離性后专,指的是一個(gè)事務(wù)的執(zhí)行不能被其他事務(wù)干擾,即一個(gè)事務(wù)內(nèi)部的操作及使用的數(shù)據(jù)對(duì)其他的并發(fā)事務(wù)是隔離的输莺。鎖和多版本控制就符合隔離性戚哎。
二、并發(fā)事務(wù)控制
1.單版本控制-鎖
先來(lái)看鎖嫂用,鎖用獨(dú)占的方式來(lái)保證在只有一個(gè)版本的情況下事務(wù)之間相互隔離型凳,所以鎖可以理解為單版本控制。
在 MySQL 事務(wù)中嘱函,鎖的實(shí)現(xiàn)與隔離級(jí)別有關(guān)系甘畅,在 RR(Repeatable Read)隔離級(jí)別下,MySQL 為了解決幻讀的問(wèn)題往弓,以犧牲并行度為代價(jià)疏唾,通過(guò) Gap 鎖來(lái)防止數(shù)據(jù)的寫入,而這種鎖函似,因?yàn)槠洳⑿卸炔粔蚧痹啵瑳_突很多,經(jīng)常會(huì)引起死鎖∑材現(xiàn)在流行的 Row 模式可以避免很多沖突甚至死鎖問(wèn)題,所以推薦默認(rèn)使用 Row + RC(Read Committed)模式的隔離級(jí)別露氮,可以很大程度上提高數(shù)據(jù)庫(kù)的讀寫并行度钟沛。
2.多版本控制-MVCC
多版本控制也叫作 MVCC,是指在數(shù)據(jù)庫(kù)中叁扫,為了實(shí)現(xiàn)高并發(fā)的數(shù)據(jù)訪問(wèn),對(duì)數(shù)據(jù)進(jìn)行多版本處理畴蒲,并通過(guò)事務(wù)的可見(jiàn)性來(lái)保證事務(wù)能看到自己應(yīng)該看到的數(shù)據(jù)版本对室。
每一次對(duì)數(shù)據(jù)庫(kù)的修改,都會(huì)在 Undo 日志中記錄當(dāng)前修改記錄的事務(wù)號(hào)及修改前數(shù)據(jù)狀態(tài)的存儲(chǔ)地址(即 ROLL_PTR)蔫骂,以便在必要的時(shí)候可以回滾到老的數(shù)據(jù)版本牺汤。例如,一個(gè)讀事務(wù)查詢到當(dāng)前記錄补胚,而最新的事務(wù)還未提交追迟,根據(jù)原子性,讀事務(wù)看不到最新數(shù)據(jù)瓶逃,但可以去回滾段中找到老版本的數(shù)據(jù)每瞒,這樣就生成了多個(gè)版本纯露。
多版本控制很巧妙地將稀缺資源的獨(dú)占互斥轉(zhuǎn)換為并發(fā)埠褪,大大提高了數(shù)據(jù)庫(kù)的吞吐量及讀寫性能。
三钞速、特性背后的技術(shù)原理
1.原子性背后的技術(shù)
每一個(gè)寫事務(wù),都會(huì)修改 Buffer Pool苹威,從而產(chǎn)生相應(yīng)的 Redo 日志驾凶,這些日志信息會(huì)被記錄到 ib_logfiles 文件中掷酗。因?yàn)?Redo 日志是遵循 Write Ahead Log 的方式寫的窟哺,所以事務(wù)是順序被記錄的且轨。
在 MySQL 中浮声,任何 Buffer Pool 中的頁(yè)被刷到磁盤之前旋奢,都會(huì)先寫入到日志文件中,這樣做有兩方面的保證黄绩。
如果 Buffer Pool 中的這個(gè)頁(yè)沒(méi)有刷成功爽丹,此時(shí)數(shù)據(jù)庫(kù)掛了筑煮,那在數(shù)據(jù)庫(kù)再次啟動(dòng)之后,可以通過(guò) Redo 日志將其恢復(fù)出來(lái)真仲,以保證臟頁(yè)寫下去的數(shù)據(jù)不會(huì)丟失初澎,所以必須要保證 Redo 先寫秸应。
因?yàn)?Buffer Pool 的空間是有限的,要載入新頁(yè)時(shí)软啼,需要從 LRU 鏈表中淘汰一些頁(yè),而這些頁(yè)必須要刷盤之后延柠,才可以重新使用,那這時(shí)的刷盤贞间,就需要保證對(duì)應(yīng)的 LSN 的日志也要提前寫到 ib_logfiles 中贿条,如果沒(méi)有寫的話增热,恰巧這個(gè)事務(wù)又沒(méi)有提交,數(shù)據(jù)庫(kù)掛了峻仇,在數(shù)據(jù)庫(kù)啟動(dòng)之后,這個(gè)事務(wù)就沒(méi)法回滾了。所以如果不寫日志的話凡蚜,這些數(shù)據(jù)對(duì)應(yīng)的回滾日志可能就不存在,導(dǎo)致未提交的事務(wù)回滾不了含鳞,從而不能保證原子性芹务,所以原子性就是通過(guò) WAL 來(lái)保證的。
2.持久性背后的技術(shù)
一個(gè)“提交”動(dòng)作觸發(fā)的操作有:binlog 落地枣抱、發(fā)送 binlog、存儲(chǔ)引擎提交桅狠、flush_logs轿秧, check_point、事務(wù)提交標(biāo)記等漩符。這些都是數(shù)據(jù)庫(kù)保證其數(shù)據(jù)完整性驱还、持久性的手段。
通過(guò)原子性可以保證邏輯上的持久性闷沥,通過(guò)存儲(chǔ)引擎的數(shù)據(jù)刷盤可以保證物理上的持久性。這個(gè)過(guò)程與前面提到的 Redo 日志颖侄、事務(wù)狀態(tài)享郊、數(shù)據(jù)庫(kù)恢復(fù)炊琉、參數(shù) innodb_flush_log_at_trx_commit 有關(guān)锰悼,還與 binlog 有關(guān)。這里多提一句箕般,在數(shù)據(jù)庫(kù)恢復(fù)時(shí)舔清,如果發(fā)現(xiàn)某事務(wù)的狀態(tài)為 Prepare体谒,則會(huì)在 binlog 中找到對(duì)應(yīng)的事務(wù)并將其在數(shù)據(jù)庫(kù)中重新執(zhí)行一遍杯聚,來(lái)保證數(shù)據(jù)庫(kù)的持久性。
3.隔離性背后的技術(shù)
接下來(lái)看隔離性,InnoDB 支持的隔離性有 4 種傀广,隔離性從低到高分別為:讀未提交、讀提交糜值、可重復(fù)讀坯墨、可串行化骄瓣。
(1)讀未提交(RU,Read Uncommitted)榕栏。它能讀到一個(gè)事務(wù)的中間過(guò)程蕾各,違背了 ACID 特性缸榛,存在臟讀的問(wèn)題敦腔,所以基本不會(huì)用到负懦,可以忽略柏腻。
(2)讀提交(RC,Read Committed)躯枢。它表示如果其他事務(wù)已經(jīng)提交锄蹂,那么我們就可以看到晰洒,朝抖,這也是一種最普遍適用的級(jí)別。但由于一些歷史原因谍珊,可能 RC 在生產(chǎn)環(huán)境中用的并不多治宣。
(3)可重復(fù)讀(RR,Repeatable Read)砌滞,是目前被使用得最多的一種級(jí)別侮邀。其特點(diǎn)是有 Gap 鎖、目前還是默認(rèn)的級(jí)別贝润、在這種級(jí)別下會(huì)經(jīng)常發(fā)生死鎖绊茧、低并發(fā)等問(wèn)題。
(4)可串行化题暖,這種實(shí)現(xiàn)方式按傅,其實(shí)已經(jīng)并不是多版本了,又回到了單版本的狀態(tài)胧卤,因?yàn)樗械膶?shí)現(xiàn)都是通過(guò)鎖來(lái)實(shí)現(xiàn)的唯绍。
注意:
- 在 RR 級(jí)別下,長(zhǎng)時(shí)間未提交的事務(wù)會(huì)影響數(shù)據(jù)庫(kù)的 PURGE 操作枝誊,從而影響數(shù)據(jù)庫(kù)的性能况芒,所以可以對(duì)這樣的事務(wù)添加一個(gè)監(jiān)控。
- 可串行化是通過(guò)鎖來(lái)實(shí)現(xiàn)的叶撒,所以實(shí)際上并不是多版本控制绝骚,它的特點(diǎn)也很明顯:讀鎖、單版本控制祠够、并發(fā)低压汪。
4.一致性背后的技術(shù)
一致性可以歸納為數(shù)據(jù)的完整性。根據(jù)前文可知古瓤,數(shù)據(jù)的完整性是通過(guò)其他三個(gè)特性來(lái)保證的止剖,包括原子性、隔離性落君、持久性穿香,而這三個(gè)特性,又是通過(guò) Redo/Undo 來(lái)保證的绎速,正所謂:合久必分皮获,分久必合,三足鼎力纹冤,三分歸晉洒宝,數(shù)據(jù)庫(kù)也是,為了保證數(shù)據(jù)的完整性萌京,提出來(lái)三個(gè)特性待德,這三個(gè)特性又是由同一個(gè)技術(shù)來(lái)實(shí)現(xiàn)的,所以理解 Redo/Undo 才能理解數(shù)據(jù)庫(kù)的本質(zhì)枫夺。
如上圖所示将宪,邏輯上的一致性,包括唯一索引橡庞、外鍵約束较坛、check 約束,這屬于業(yè)務(wù)邏輯范疇扒最,這里就不做贅述了丑勤。
四、MVCC 實(shí)現(xiàn)原理
MySQL InnoDB 存儲(chǔ)引擎吧趣,實(shí)現(xiàn)的是基于多版本的并發(fā)控制協(xié)議——MVCC法竞,而不是基于鎖的并發(fā)控制耙厚。
MVCC 最大的好處是讀不加鎖,讀寫不沖突岔霸。在讀多寫少的 OLTP(On-Line Transaction Processing)應(yīng)用中薛躬,讀寫不沖突是非常重要的,極大的提高了系統(tǒng)的并發(fā)性能呆细,這也是為什么現(xiàn)階段幾乎所有的 RDBMS(Relational Database Management System)型宝,都支持 MVCC 的原因。
1.快照讀與當(dāng)前讀
在 MVCC 并發(fā)控制中絮爷,讀操作可以分為兩類: 快照讀(Snapshot Read)與當(dāng)前讀 (Current Read)趴酣。
- 快照讀:讀取的是記錄的可見(jiàn)版本(有可能是歷史版本),不用加鎖坑夯。- - 當(dāng)前讀:讀取的是記錄的最新版本岖寞,并且當(dāng)前讀返回的記錄,都會(huì)加鎖柜蜈,保證其他事務(wù)不會(huì)再并發(fā)修改這條記錄慎璧。
注意: MVCC 只在 Read Commited 和 Repeatable Read 兩種隔離級(jí)別下工作。
區(qū)別: - 快照讀:簡(jiǎn)單的 select 操作跨释,屬于快照讀胸私,不需要加鎖。
- 當(dāng)前讀:特殊的讀操作鳖谈,插入/更新/刪除操作岁疼,屬于當(dāng)前讀,需要加鎖缆娃。
2.MVCC 多版本實(shí)現(xiàn)
以“事務(wù)對(duì)某行記錄更新的過(guò)程””為例
- 假設(shè) F1~F6 是表中字段的名字捷绒,1~6 是其對(duì)應(yīng)的數(shù)據(jù)。后面三個(gè)隱含字段分別對(duì)應(yīng)該行的隱含ID贯要、事務(wù)號(hào)和回滾指針暖侨,如下圖所示。
隱含 ID(DB_ROW_ID)崇渗,6 個(gè)字節(jié)字逗,當(dāng)由 InnoDB 自動(dòng)產(chǎn)生聚集索引時(shí),聚集索引包括這個(gè) DB_ROW_ID 的值宅广。
事務(wù)號(hào)(DB_TRX_ID)葫掉,6 個(gè)字節(jié),標(biāo)記了最新更新這條行記錄的 Transaction ID跟狱,每處理一個(gè)事務(wù)俭厚,其值自動(dòng) +1。
回滾指針(DB_ROLL_PT)驶臊,7 個(gè)字節(jié)挪挤,指向當(dāng)前記錄項(xiàng)的 Rollback Segment 的 Undo log記錄叼丑,通過(guò)這個(gè)指針才能查找之前版本的數(shù)據(jù)。
具體的更新過(guò)程扛门,簡(jiǎn)單描述如下鸠信。
首先,假如這條數(shù)據(jù)是剛 INSERT 的尖飞,可以認(rèn)為 ID 為 1症副,其他兩個(gè)字段為空店雅。
然后政基,當(dāng)事務(wù) 1 更改該行的數(shù)據(jù)值時(shí),會(huì)進(jìn)行如下操作闹啦,如下圖所示沮明。
用排他鎖鎖定該行;記錄 Redo log窍奋;
把該行修改前的值復(fù)制到 Undo log荐健,即圖中下面的行;
修改當(dāng)前行的值琳袄,填寫事務(wù)編號(hào)江场,使回滾指針指向 Undo log 中修改前的行。
接下來(lái)窖逗,與事務(wù) 1 相同址否,此時(shí) Undo log 中有兩行記錄,并且通過(guò)回滾指針連在一起碎紊。因此佑附,如果 Undo log 一直不刪除,則會(huì)通過(guò)當(dāng)前記錄的回滾指針回溯到該行創(chuàng)建時(shí)的初始內(nèi)容仗考,所幸的是在 InnoDB 中存在 purge 線程音同,它會(huì)查詢那些比現(xiàn)在最老的活動(dòng)事務(wù)還早的 Undo log,并刪除它們秃嗜,從而保證 Undo log 文件不會(huì)無(wú)限增長(zhǎng)权均,如下圖所示。
并發(fā)事務(wù)問(wèn)題及解決方案
上文講述了 MVCC 的原理及其實(shí)現(xiàn)锅锨。那么隨著數(shù)據(jù)庫(kù)并發(fā)事務(wù)處理能力的大大增強(qiáng)螺句,數(shù)據(jù)庫(kù)資源的利用率也會(huì)大大提高,從而提高了數(shù)據(jù)庫(kù)系統(tǒng)的事務(wù)吞吐量橡类,可以支持更多的用戶并發(fā)訪問(wèn)蛇尚。但并發(fā)事務(wù)處理也會(huì)帶來(lái)一些問(wèn)題,如:臟讀顾画、不可重復(fù)讀、幻讀。下面一一解釋其含義一疯。
臟讀
一個(gè)事務(wù)正在對(duì)一條記錄做修改琳要,在這個(gè)事務(wù)完成并提交前,這條記錄的數(shù)據(jù)就處于不一致?tīng)顟B(tài)慌随;這時(shí),另一個(gè)事務(wù)也來(lái)讀取同一條記錄,如果不加控制咆课,第二個(gè)事務(wù)讀取了這些“臟”數(shù)據(jù),并據(jù)此做進(jìn)一步的處理扯俱,就會(huì)產(chǎn)生未提交的數(shù)據(jù)依賴關(guān)系书蚪。這種現(xiàn)象被形象的叫作'臟讀'(Dirty Reads)。
不可重復(fù)讀
一個(gè)事務(wù)在讀取某些數(shù)據(jù)后的某個(gè)時(shí)間迅栅,再次讀取以前讀過(guò)的數(shù)據(jù)殊校,卻發(fā)現(xiàn)其讀出的數(shù)據(jù)已經(jīng)發(fā)生了改變、或某些記錄已經(jīng)被刪除了读存!這種現(xiàn)象就叫作“ 不可重復(fù)讀”(Non-Repeatable Reads)为流。
幻讀
一個(gè)事務(wù)按相同的查詢條件重新讀取以前檢索過(guò)的數(shù)據(jù),卻發(fā)現(xiàn)其他事務(wù)插入了滿足其查詢條件的新數(shù)據(jù)让簿,這種現(xiàn)象就稱為“幻讀”(Phantom Reads)敬察。
解決方案
產(chǎn)生的這些問(wèn)題,MySQL 數(shù)據(jù)庫(kù)是通過(guò)事務(wù)隔離級(jí)別來(lái)解決的尔当,上文已經(jīng)詳細(xì)講解過(guò)莲祸,這里再進(jìn)行簡(jiǎn)單的說(shuō)明。
在上文講 MySQL 事務(wù)特性的隔離性的時(shí)候就已經(jīng)詳細(xì)地講解了事務(wù)的四種隔離級(jí)別居凶。這里要求大家能夠記住這種關(guān)系的矩陣表虫给;記住各種事務(wù)隔離級(jí)別及各自都解決了什么問(wèn)題,如下圖所示侠碧。
這里舉例說(shuō)明“臟讀”和“不可重復(fù)讀”的問(wèn)題抹估。
MySQL 中默認(rèn)的事務(wù)隔離級(jí)別是 RR,這里設(shè)置成 RC 隔離級(jí)別弄兜,此時(shí)提交事務(wù) B 修改 id=1 的數(shù)據(jù)之后药蜻,事務(wù) A 進(jìn)行同樣的查詢操作,后一次和前一次的查詢結(jié)果不一樣替饿,這就是不可重復(fù)讀(重新讀取產(chǎn)生的結(jié)果不一樣了)语泽。這里事務(wù) A 讀到了事務(wù) B 提交的數(shù)據(jù),即是“臟讀”视卢。
上文講解了不可重復(fù)讀的情況踱卵,下面我們來(lái)看看在RR隔離級(jí)別下的情況。當(dāng) teacher_id=1時(shí),事務(wù) A 先進(jìn)行一次讀取操作惋砂,事務(wù) B 中間修改了 id=1 的數(shù)據(jù)并提交妒挎,事務(wù) C 也插入了一條數(shù)據(jù)并提交。事務(wù) A 第二次讀到的數(shù)據(jù)和第一次完全相同西饵。所以說(shuō)它是可重讀的酝掩。
這里我們舉個(gè)例子來(lái)說(shuō)明“幻讀”的問(wèn)題。
行鎖可以防止不同事務(wù)版本的數(shù)據(jù)在修改提交時(shí)造成數(shù)據(jù)沖突的情況眷柔。但如何避免別的事務(wù)插入數(shù)據(jù)造成的問(wèn)題呢期虾。我們先來(lái)看看在 RC 隔離級(jí)別下的處理過(guò)程。
如下圖所示驯嘱,事務(wù) A 修改了所有 teacher_id=30 的數(shù)據(jù)镶苞,但是當(dāng)事務(wù) B INSERT 新數(shù)據(jù)后,事務(wù) A 發(fā)現(xiàn)莫名其妙的多了一行 teacher_id=30 的數(shù)據(jù)宙拉, 而且沒(méi)有被之前的 UPDATE語(yǔ)句所修改宾尚,這就是“當(dāng)前讀”的幻讀問(wèn)題丙笋。
跟上面的例子一樣谢澈,也是在 RC 事務(wù)隔離級(jí)別下,這時(shí)事務(wù) B INSERT 了一條數(shù)據(jù)御板,并提交锥忿,而事務(wù) A 讀到了事務(wù) B 新插入的數(shù)據(jù)。這也是幻讀怠肋,如下圖所示敬鬓。
這里就需要重點(diǎn)注意不可重復(fù)讀和幻讀的區(qū)別了。前面講了它們的含義笙各,這個(gè)提醒大家的是:不可重復(fù)讀重點(diǎn)在于 UPDATA 和 DELETE钉答,而幻讀的重點(diǎn)在于 INSERT。它們之間最大的區(qū)別是如何通過(guò)鎖機(jī)制來(lái)解決它們產(chǎn)生的問(wèn)題杈抢。這里說(shuō)的鎖只是使用悲觀鎖機(jī)制数尿。
那么在 RR 隔離級(jí)別下,事務(wù) A 在 UPDATE 后加鎖惶楼,事務(wù) B 無(wú)法插入新數(shù)據(jù)右蹦,這樣事務(wù) A在 UPDATE 前后讀的數(shù)據(jù)保持一致,避免了幻讀歼捐。
跟上面的案例一樣何陆,也是在 RR 事務(wù)隔離級(jí)別下,事務(wù) A 在 UPDATE 后加鎖豹储,對(duì)于其他兩個(gè)事務(wù)贷盲,事務(wù) B 和事務(wù) C 的 INSERT 操作,就必須等事務(wù) A 提交后剥扣,才能繼續(xù)執(zhí)行巩剖。這里就用到了“鎖”慨灭,這里使用的是 Gap 鎖,后面會(huì)詳細(xì)講解球及。它和上面的情況一樣氧骤,解決了“幻讀”的發(fā)生,如下圖所示吃引。