系統(tǒng)原理-MVCC

  • 在SQL標(biāo)準(zhǔn)中,RR是無(wú)法避免幻讀問(wèn)題的鸣驱,但是InnoDB實(shí)現(xiàn)的RR避免了幻讀問(wèn)題泛鸟。
  • RR解決臟讀、不可重復(fù)讀踊东、幻讀等問(wèn)題北滥,使用的是MVCC:MVCC全稱Multi-Version Concurrency Control,即多版本的并發(fā)控制協(xié)議递胧。
  • 多版本并發(fā)控制(Multi-Version Concurrency Control, MVCC)是 MySQL 的 InnoDB 存儲(chǔ)引擎實(shí)現(xiàn)隔離級(jí)別的一種具體方式碑韵,用于實(shí)現(xiàn)提交讀和可重復(fù)讀這兩種隔離級(jí)別。

https://github.com/CyC2018/CS-Notes/blob/master/notes/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F%E5%8E%9F%E7%90%86.md#%E4%BA%94%E5%A4%9A%E7%89%88%E6%9C%AC%E5%B9%B6%E5%8F%91%E6%8E%A7%E5%88%B6


基本思想
加鎖能解決多個(gè)事務(wù)同時(shí)執(zhí)行時(shí)出現(xiàn)的并發(fā)一致性問(wèn)題缎脾。在實(shí)際場(chǎng)景中讀操作往往多于寫(xiě)操作祝闻,因此又引入了讀寫(xiě)鎖來(lái)避免不必要的加鎖操作,例如讀和讀沒(méi)有互斥關(guān)系遗菠。讀寫(xiě)鎖中讀和寫(xiě)操作仍然是互斥的联喘,而 MVCC 利用了多版本的思想,寫(xiě)操作更新最新的版本快照辙纬,而讀操作去讀舊版本快照豁遭,沒(méi)有互斥關(guān)系,這一點(diǎn)和 CopyOnWrite 類似贺拣。

在 MVCC 中事務(wù)的修改操作(DELETE蓖谢、INSERT、UPDATE)會(huì)為數(shù)據(jù)行新增一個(gè)版本快照譬涡。

臟讀和不可重復(fù)讀最根本的原因是事務(wù)讀取到其它事務(wù)未提交的修改闪幽。在事務(wù)進(jìn)行讀取操作時(shí),為了解決臟讀和不可重復(fù)讀問(wèn)題涡匀,MVCC 規(guī)定只能讀取已經(jīng)提交的快照盯腌。當(dāng)然一個(gè)事務(wù)可以讀取自身未提交的快照,這不算是臟讀陨瘩。


特點(diǎn):在同一時(shí)刻腕够,不同事務(wù)讀取到的數(shù)據(jù)可能是不同的(即多版本)
實(shí)現(xiàn):通過(guò)保存數(shù)據(jù)在某個(gè)時(shí)間點(diǎn)的快照來(lái)實(shí)現(xiàn)


版本號(hào)

  • 系統(tǒng)版本號(hào)SYS_ID:遞增數(shù)字,每開(kāi)始一個(gè)新的事務(wù)舌劳,系統(tǒng)版本號(hào)就會(huì)自動(dòng)遞增帚湘。
  • 事務(wù)版本號(hào)TRX_ID:事務(wù)開(kāi)始時(shí)的系統(tǒng)版本號(hào)。

Undo日志
MVCC 的多版本指的是多個(gè)版本的快照甚淡,快照存儲(chǔ)在 Undo 日志中客们,該日志通過(guò)回滾指針 ROLL_PTR 把一個(gè)數(shù)據(jù)行的所有快照連接起來(lái)。

例如在 MySQL 創(chuàng)建一個(gè)表 t,包含主鍵 id 和一個(gè)字段 x底挫。我們先插入一個(gè)數(shù)據(jù)行恒傻,然后對(duì)該數(shù)據(jù)行執(zhí)行兩次更新操作导帝。

INSERT INTO t(id, x) VALUES(1, "a");
UPDATE t SET x="b" WHERE id=1;
UPDATE t SET x="c" WHERE id=1;

因?yàn)闆](méi)有使用 START TRANSACTION 將上面的操作當(dāng)成一個(gè)事務(wù)來(lái)執(zhí)行既穆,根據(jù) MySQL 的 AUTOCOMMIT 機(jī)制岩灭,每個(gè)操作都會(huì)被當(dāng)成一個(gè)事務(wù)來(lái)執(zhí)行椭住,所以上面的操作總共涉及到三個(gè)事務(wù)客燕》锞蓿快照中除了記錄事務(wù)版本號(hào) TRX_ID 和操作之外内边,還記錄了一個(gè) bit 的 DEL 字段票灰,用于標(biāo)記是否被刪除注簿。

INSERT契吉、UPDATE、DELETE 操作會(huì)創(chuàng)建一個(gè)日志诡渴,并將事務(wù)版本號(hào) TRX_ID 寫(xiě)入捐晶。DELETE 可以看成是一個(gè)特殊的 UPDATE,還會(huì)額外將 DEL 字段設(shè)置為 1妄辩。


InnoDB實(shí)現(xiàn)MVCC
MVCC最大的優(yōu)點(diǎn)是讀不加鎖惑灵,因此讀寫(xiě)不沖突,并發(fā)性能好眼耀。InnoDB實(shí)現(xiàn)MVCC英支,多個(gè)版本的數(shù)據(jù)可以共存,主要基于以下技術(shù)及數(shù)據(jù)結(jié)構(gòu):

1)隱藏列:InnoDB中每行數(shù)據(jù)都有隱藏列哮伟,隱藏列中包含了本行數(shù)據(jù)的事務(wù)id干花、指向undo log的指針等。

2)基于undo log的版本鏈:前面說(shuō)到每行數(shù)據(jù)的隱藏列中包含了指向undo log的指針楞黄,而每條undo log也會(huì)指向更早版本的undo log池凄,從而形成一條版本鏈。

3)ReadView:通過(guò)隱藏列和版本鏈谅辣,MySQL可以將數(shù)據(jù)恢復(fù)到指定版本;但是具體要恢復(fù)到哪個(gè)版本婶恼,則需要根據(jù)ReadView來(lái)確定桑阶。所謂ReadView勾邦,是指事務(wù)(記做事務(wù)A)在某一時(shí)刻給整個(gè)事務(wù)系統(tǒng)(trx_sys)打快照蚣录,之后再進(jìn)行讀操作時(shí),會(huì)將讀取到的數(shù)據(jù)中的事務(wù)id與trx_sys快照比較眷篇,從而判斷數(shù)據(jù)對(duì)該ReadView是否可見(jiàn)萎河,即對(duì)事務(wù)A是否可見(jiàn)。

trx_sys中的主要內(nèi)容,以及判斷可見(jiàn)性的方法如下:

  • low_limit_id:表示生成ReadView時(shí)系統(tǒng)中應(yīng)該分配給下一個(gè)事務(wù)的id虐杯。如果數(shù)據(jù)的事務(wù)id大于等于low_limit_id玛歌,則對(duì)該ReadView不可見(jiàn)。
  • up_limit_id:表示生成ReadView時(shí)當(dāng)前系統(tǒng)中活躍的讀寫(xiě)事務(wù)中最小的事務(wù)id擎椰。如果數(shù)據(jù)的事務(wù)id小于up_limit_id支子,則對(duì)該ReadView可見(jiàn)。
  • rw_trx_ids:表示生成ReadView時(shí)當(dāng)前系統(tǒng)中活躍的讀寫(xiě)事務(wù)的事務(wù)id列表达舒。如果數(shù)據(jù)的事務(wù)id在low_limit_id和up_limit_id之間值朋,則需要判斷事務(wù)id是否在rw_trx_ids中:如果在,說(shuō)明生成ReadView時(shí)事務(wù)仍在活躍中巩搏,因此數(shù)據(jù)對(duì)ReadView不可見(jiàn)昨登;如果不在,說(shuō)明生成ReadView時(shí)事務(wù)已經(jīng)提交了贯底,因此數(shù)據(jù)對(duì)ReadView可見(jiàn)丰辣。

擴(kuò)展

前面介紹的MVCC,是RR隔離級(jí)別下“非加鎖讀”實(shí)現(xiàn)隔離性的方式丈甸。下面是一些簡(jiǎn)單的擴(kuò)展糯俗。

(1)讀已提交(RC)隔離級(jí)別下的非加鎖讀

RC與RR一樣,都使用了MVCC睦擂,其主要區(qū)別在于:

RR是在事務(wù)開(kāi)始后第一次執(zhí)行select前創(chuàng)建ReadView得湘,直到事務(wù)提交都不會(huì)再創(chuàng)建。根據(jù)前面的介紹顿仇,RR可以避免臟讀淘正、不可重復(fù)讀和幻讀。

RC每次執(zhí)行select前都會(huì)重新建立一個(gè)新的ReadView臼闻,因此如果事務(wù)A第一次select之后鸿吆,事務(wù)B對(duì)數(shù)據(jù)進(jìn)行了修改并提交,那么事務(wù)A第二次select時(shí)會(huì)重新建立新的ReadView述呐,因此事務(wù)B的修改對(duì)事務(wù)A是可見(jiàn)的惩淳。因此RC隔離級(jí)別可以避免臟讀,但是無(wú)法避免不可重復(fù)讀和幻讀乓搬。

(2)加鎖讀與next-key lock

按照是否加鎖思犁,MySQL的讀可以分為兩種:

一種是非加鎖讀,也稱作快照讀进肯、一致性讀激蹲,使用普通的select語(yǔ)句,這種情況下使用MVCC避免了臟讀江掩、不可重復(fù)讀学辱、幻讀乘瓤,保證了隔離性。

另一種是加鎖讀策泣,查詢語(yǔ)句有所不同衙傀,如下所示:

#共享鎖讀取
select...lock in share mode

#排它鎖讀取
select...for update

加鎖讀在查詢時(shí)會(huì)對(duì)查詢的數(shù)據(jù)加鎖(共享鎖或排它鎖)。由于鎖的特性着降,當(dāng)某事務(wù)對(duì)數(shù)據(jù)進(jìn)行加鎖讀后差油,其他事務(wù)無(wú)法對(duì)數(shù)據(jù)進(jìn)行寫(xiě)操作,因此可以避免臟讀和不可重復(fù)讀任洞。而避免幻讀蓄喇,則需要通過(guò)next-key lock。next-key lock是行鎖的一種交掏,實(shí)現(xiàn)相當(dāng)于record lock(記錄鎖) + gap lock(間隙鎖)妆偏;其特點(diǎn)是不僅會(huì)鎖住記錄本身(record lock的功能),還會(huì)鎖定一個(gè)范圍(gap lock的功能)盅弛。因此钱骂,加鎖讀同樣可以避免臟讀、不可重復(fù)讀和幻讀挪鹏,保證隔離性见秽。


總結(jié)

概括來(lái)說(shuō),InnoDB實(shí)現(xiàn)的RR讨盒,通過(guò)鎖機(jī)制(包含next-key lock)解取、MVCC(包括數(shù)據(jù)的隱藏列、基于undo log的版本鏈返顺、ReadView)等禀苦,實(shí)現(xiàn)了一定程度的隔離性,可以滿足大多數(shù)場(chǎng)景的需要遂鹊。

不過(guò)需要說(shuō)明的是振乏,RR雖然避免了幻讀問(wèn)題,但是畢竟不是Serializable秉扑,不能保證完全的隔離慧邮,下面是一個(gè)例子:

  • 如果在事務(wù)中第一次讀取采用非加鎖讀,第二次讀取采用加鎖讀舟陆,則如果在兩次讀取之間數(shù)據(jù)發(fā)生了變化误澳,兩次讀取到的結(jié)果不一樣,因?yàn)榧渔i讀時(shí)不會(huì)采用MVCC吨娜。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末脓匿,一起剝皮案震驚了整個(gè)濱河市淘钟,隨后出現(xiàn)的幾起案子宦赠,更是在濱河造成了極大的恐慌陪毡,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勾扭,死亡現(xiàn)場(chǎng)離奇詭異毡琉,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)妙色,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)桅滋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人身辨,你說(shuō)我怎么就攤上這事丐谋。” “怎么了煌珊?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵号俐,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我定庵,道長(zhǎng)吏饿,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任蔬浙,我火速辦了婚禮猪落,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘畴博。我一直安慰自己笨忌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布绎晃。 她就那樣靜靜地躺著蜜唾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪庶艾。 梳的紋絲不亂的頭發(fā)上袁余,一...
    開(kāi)封第一講書(shū)人閱讀 49,785評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音咱揍,去河邊找鬼颖榜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛煤裙,可吹牛的內(nèi)容都是我干的掩完。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼硼砰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼且蓬!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起题翰,我...
    開(kāi)封第一講書(shū)人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤恶阴,失蹤者是張志新(化名)和其女友劉穎诈胜,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體冯事,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡焦匈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了昵仅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缓熟。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖摔笤,靈堂內(nèi)的尸體忽然破棺而出够滑,到底是詐尸還是另有隱情,我是刑警寧澤吕世,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布版述,位于F島的核電站,受9級(jí)特大地震影響寞冯,放射性物質(zhì)發(fā)生泄漏渴析。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一吮龄、第九天 我趴在偏房一處隱蔽的房頂上張望俭茧。 院中可真熱鬧,春花似錦漓帚、人聲如沸母债。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)毡们。三九已至,卻和暖如春昧辽,著一層夾襖步出監(jiān)牢的瞬間衙熔,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工搅荞, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留红氯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓咕痛,卻偏偏與公主長(zhǎng)得像痢甘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子茉贡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容