MVCC 能解決幻讀嗎萨咳?

昨天面試當(dāng)中一個小伙認(rèn)為MVCC可以解決RR中的幻讀問題, 先說結(jié)論信姓, MVCC不能解決幻讀,很遺憾還是得用鎖绸罗。 下面詳細(xì)描述一下意推。
InnoDB的MVCC, 實(shí)現(xiàn)的是基于多版本的并發(fā)控制協(xié)議——MVCC (Multi-Version Concurrency Control) (注:與MVCC相對的,是基于鎖的并發(fā)控制珊蟀,Lock-Based Concurrency Control)菊值, 用于支持RC和RR隔離級別的實(shí)現(xiàn)。 在一個支持MVCC的并發(fā)系統(tǒng)中系洛, 我們需要支持兩種讀俊性, 一個是快照讀, 一個是當(dāng)前讀描扯。
快照讀:簡單的select操作定页,屬于快照讀,不加鎖绽诚。
當(dāng)前讀:特殊的讀操作典徊,插入/更新/刪除操作,屬于當(dāng)前讀恩够,需要加鎖卒落, 讀取的是最新數(shù)據(jù)。
在innodb中蜂桶,MVCC其實(shí)是通過undo log來實(shí)現(xiàn)的儡毕, 解釋起來會比較復(fù)雜, 不過我在別的博客看到一個很簡潔的解釋方式, 理解起來可以認(rèn)為是通過在每行記錄后面保存兩個隱藏的列來實(shí)現(xiàn)的,這兩個列腰湾,分別保存了這個行的創(chuàng)建時間雷恃,一個保存的是行的刪除時間。這里存儲的并不是實(shí)際的時間值,而是系統(tǒng)版本號(可以理解為事務(wù)的ID)费坊,每開始一個新的事務(wù)倒槐,系統(tǒng)版本號就會自動遞增,事務(wù)開始時刻的系統(tǒng)版本號會作為事務(wù)的ID.
以下內(nèi)容取RR隔離級別附井, 當(dāng)然RC也是同理讨越,只不過select的選定范圍不同。
對應(yīng)在數(shù)據(jù)中的表如下(后面兩列是隱藏列,我們通過查詢語句并看不到)

id name 創(chuàng)建時間(事務(wù)ID) 刪除時間(事務(wù)ID)
1 yang 1 undefined
2 long 1 undefined
3 fei 1 undefined

SELECT

InnoDB會根據(jù)以下兩個條件檢查每行記錄:

  1. InnoDB只會查找版本早于當(dāng)前事務(wù)版本的數(shù)據(jù)行(也就是,行的系統(tǒng)版本號小于或等于事務(wù)的系統(tǒng)版本號)永毅,這樣可以確保事務(wù)讀取的行把跨,要么是在事務(wù)開始前已經(jīng)存在的,要么是事務(wù)自身插入或者修改過的.

  2. 行的刪除版本要么未定義,要么大于當(dāng)前事務(wù)版本號(這可以確保事務(wù)讀取到的行卷雕,在事務(wù)開始之前未被刪除)节猿,
    只有條件1、2同時滿足的記錄漫雕,才能返回作為查詢結(jié)果.

DELETE

InnoDB會為刪除的每一行保存當(dāng)前系統(tǒng)的版本號(事務(wù)的ID)作為刪除標(biāo)識.

看下面的具體例子分析: 第二個事務(wù),ID為2:

start transaction; 
select * from yang; 
select * from yang; 
commit;

假設(shè)1:
假設(shè)在執(zhí)行這個事務(wù)ID為2的過程中,剛執(zhí)行到(1),這時,有另一個事務(wù)ID為3往這個表里插入了一條數(shù)據(jù); 第三個事務(wù)ID為3;

start transaction;
insert into yang values(NULL,'tian');
commit;

這時表中的數(shù)據(jù)如下:

id name 創(chuàng)建時間(事務(wù)ID) 刪除時間(事務(wù)ID)
1 yang 1 undefined
2 long 1 undefined
3 fei 1 undefined
4 tian 3 undefined

然后接著執(zhí)行事務(wù)2中的(2),由于id=4的數(shù)據(jù)的創(chuàng)建時間(事務(wù)ID為3),執(zhí)行當(dāng)前事務(wù)的ID為2,而InnoDB只會查找事務(wù)ID小于等于當(dāng)前事務(wù)ID的數(shù)據(jù)行,所以id=4的數(shù)據(jù)行并不會在執(zhí)行事務(wù)2中的(2)被檢索出來,在事務(wù)2中的兩條select 語句檢索出來的數(shù)據(jù)如下:

id name 創(chuàng)建時間(事務(wù)ID) 刪除時間(事務(wù)ID)
1 yang 1 undefined
2 long 1 undefined
3 fei 1 undefined

假設(shè)2
假設(shè)在執(zhí)行這個事務(wù)ID為2的過程中,剛執(zhí)行到(1),假設(shè)事務(wù)執(zhí)行完事務(wù)3后滨嘱,接著又執(zhí)行了事務(wù)4;
第四個事務(wù):

start transaction; 
delete from yang where id=1; 
commit;

此時數(shù)據(jù)庫中的表如下:

id name 創(chuàng)建時間(事務(wù)ID) 刪除時間(事務(wù)ID)
1 yang 1 4
2 long 1 undefined
3 fei 1 undefined
4 tian 3 undefined

接著執(zhí)行事務(wù)ID為2的事務(wù)(2),根據(jù)SELECT 檢索條件可以知道,它會檢索創(chuàng)建時間(創(chuàng)建事務(wù)的ID)小于當(dāng)前事務(wù)ID的行和刪除時間(刪除事務(wù)的ID)大于當(dāng)前事務(wù)的行,而id=4的行上面已經(jīng)說過,而id=1的行由于刪除時間(刪除事務(wù)的ID)大于當(dāng)前事務(wù)的ID,所以事務(wù)2的(2)select * from yang也會把id=1的數(shù)據(jù)檢索出來.所以,事務(wù)2中的兩條select 語句檢索出來的數(shù)據(jù)都如下:

id name 創(chuàng)建時間(事務(wù)ID) 刪除時間(事務(wù)ID)
1 yang 1 4
2 long 1 undefined
3 fei 1 undefined

UPDATE

InnoDB執(zhí)行UPDATE,實(shí)際上是新插入了一行記錄浸间,并保存其創(chuàng)建時間為當(dāng)前事務(wù)的ID太雨,同時保存當(dāng)前事務(wù)ID到要UPDATE的行的刪除時間。
假設(shè)3:
假設(shè)在執(zhí)行完事務(wù)2的(1)后又執(zhí)行,其它用戶執(zhí)行了事務(wù)3,4,這時魁蒜,又有一個用戶對這張表執(zhí)行了UPDATE操作:
第5個事務(wù):

start transaction; 
update yang set name='Long' where id=2;
commit;

根據(jù)update的更新原則:會生成新的一行,并在原來要修改的列的刪除時間列上添加本事務(wù)ID,得到表如下:

id name 創(chuàng)建時間(事務(wù)ID) 刪除時間(事務(wù)ID)
1 yang 1 4
2 long 1 5
3 fei 1 undefined
4 tian 3 undefined
2 Long 5 undefined

繼續(xù)執(zhí)行事務(wù)2的(2),根據(jù)select 語句的檢索條件,得到下表:

id name 創(chuàng)建時間(事務(wù)ID) 刪除時間(事務(wù)ID)
1 yang 1 4
2 long 1 5
3 fei 1 undefined

還是和事務(wù)2中(1)select 得到相同的結(jié)果.

INSERT

我們知道幻讀都是發(fā)生在insert之后的囊扳, 我們回到假設(shè)1當(dāng)中, 可以看到事務(wù)3插入了一條新的數(shù)據(jù)兜看。
假設(shè)4:
假設(shè)在執(zhí)行完第3個事務(wù)之后又開始執(zhí)行第二個事務(wù)(添加兩條語句)
第2個事務(wù):

start transaction; 
select * from yang; 
select * from yang; 
(事物3已結(jié)commit了)
//新添加語句
update yang set name='Tian' where id=4;
select * from yang; 
commit;

根據(jù)update的更新原則:會生成新的一行,并在原來要修改的列的刪除時間列上添加本事務(wù)ID,得到表如下:

id name 創(chuàng)建時間(事務(wù)ID) 刪除時間(事務(wù)ID)
1 yang 1 undefined
2 long 1 undefined
3 fei 1 undefined
4 tian 3 2
4 Tian 2 undefined

繼續(xù)執(zhí)行事務(wù)2的(2),根據(jù)select 語句的檢索條件,得到下表:

id name 創(chuàng)建時間(事務(wù)ID) 刪除時間(事務(wù)ID)
1 yang 1 undefined
2 long 1 undefined
3 fei 1 undefined
4 Tian 2 undefined

可見發(fā)生了幻讀锥咸。 原因就是事務(wù)2中的update是當(dāng)前讀, 會操作最新數(shù)據(jù)细移, 所以造成了幻讀

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末搏予,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子弧轧,更是在濱河造成了極大的恐慌雪侥,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件精绎,死亡現(xiàn)場離奇詭異速缨,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)代乃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門旬牲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事引谜‰鼓埃” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵员咽,是天一觀的道長。 經(jīng)常有香客問我贮预,道長贝室,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任仿吞,我火速辦了婚禮滑频,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘唤冈。我一直安慰自己峡迷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布你虹。 她就那樣靜靜地躺著绘搞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪傅物。 梳的紋絲不亂的頭發(fā)上夯辖,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機(jī)與錄音董饰,去河邊找鬼蒿褂。 笑死,一個胖子當(dāng)著我的面吹牛卒暂,可吹牛的內(nèi)容都是我干的啄栓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼也祠,長吁一口氣:“原來是場噩夢啊……” “哼昙楚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起齿坷,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤桂肌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后永淌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崎场,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年遂蛀,在試婚紗的時候發(fā)現(xiàn)自己被綠了谭跨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖螃宙,靈堂內(nèi)的尸體忽然破棺而出蛮瞄,到底是詐尸還是另有隱情,我是刑警寧澤谆扎,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布挂捅,位于F島的核電站,受9級特大地震影響堂湖,放射性物質(zhì)發(fā)生泄漏闲先。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一无蜂、第九天 我趴在偏房一處隱蔽的房頂上張望伺糠。 院中可真熱鬧,春花似錦斥季、人聲如沸训桶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舵揭。三九已至,卻和暖如春灶挟,著一層夾襖步出監(jiān)牢的瞬間琉朽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工稚铣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留箱叁,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓惕医,卻偏偏與公主長得像耕漱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子抬伺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

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