mysql:innodb存儲(chǔ)引擎 事務(wù)隔離級(jí)別與mvcc

1. 事務(wù)隔離級(jí)別

四種隔離級(jí)別及對(duì)應(yīng)問題的可能性养叛。

隔離級(jí)別 臟讀 不可重復(fù)讀 幻讀
讀未提交 可能 可能 可能
讀已提交 不可能 可能 可能
可重復(fù)讀 不可能 不可能 可能
串行化 不可能 不可能 不可能

2. 快照讀(非鎖定讀, 普通select語句)

一致性非鎖定讀是通過MVCC來讀取數(shù)據(jù)庫中對(duì)當(dāng)前事務(wù)而言可讀版本中最新數(shù)據(jù)水评。在查詢時(shí),有其他事務(wù)正在完成寫入具壮,那么不會(huì)等待行鎖的釋放匾旭,而是讀取舊一點(diǎn)版本的數(shù)據(jù)溯壶。

2.1 undo log

innodb中及皂,當(dāng)事務(wù)提交時(shí)甫男,需要先將該事務(wù)的所有操作日志寫入到重做日志文件且改,然后等提交操作完成,事務(wù)才算完成板驳。這里的重做日志文件包含了兩部分:redo log和undo log又跛。 redo log被用來保證事物的持久性,undo log用來幫助實(shí)現(xiàn)事務(wù)回滾和MVCC若治。這里重點(diǎn)講一下undo log, 當(dāng)事務(wù)回滾時(shí)慨蓝,利用undo邏輯地將數(shù)據(jù)庫恢復(fù)到之前的狀態(tài)。
那么如何通過undo 來回滾和實(shí)現(xiàn)MVCC呢端幼。 聚簇索引記錄中都包含兩個(gè)必要的隱藏列:

  • trx_id:每次對(duì)某條聚簇索引記錄進(jìn)行改動(dòng)時(shí)礼烈,都會(huì)把對(duì)應(yīng)的事務(wù)id賦值給trx_id隱藏列。
  • roll_pointer:每次對(duì)某條聚簇索引記錄進(jìn)行改動(dòng)時(shí)婆跑,都會(huì)把舊的版本寫入到undo日志中此熬,然后這個(gè)隱藏列就相當(dāng)于一個(gè)指針,可以通過它來找到該記錄修改前的信息滑进。
聚簇索引trx_id和roll_pointer

每次對(duì)記錄進(jìn)行改動(dòng)時(shí)犀忱,生成對(duì)應(yīng)的undo log, undo log中同樣有roll pointer扶关,指向了更早的一個(gè)版本阴汇。于是就形成了一個(gè)鏈表。


版本鏈

事務(wù)回滾時(shí)节槐,邏輯地刪除該版本鏈中對(duì)應(yīng)trx_id的數(shù)據(jù)就行了搀庶。

2.2 MVCC

  • read uncommitted級(jí)別下, 直接讀取版本鏈中的頭節(jié)點(diǎn)就好了铜异。

  • read committed級(jí)別下哥倔, MVCC在每個(gè)select執(zhí)行時(shí),先創(chuàng)建一個(gè)read view熙掺。 read view 包含了以下信息:

    • 當(dāng)前事務(wù)id: cur_trx_id
    • 當(dāng)前系統(tǒng)中最小的活躍事務(wù)id: min_active_trx_id
    • 當(dāng)前系統(tǒng)中最大事務(wù)id: max_trx_id
      通過read view未斑,可以確定哪些事務(wù)寫入的數(shù)據(jù)是本次select可讀的:readable_trx = (0, min_active_trx_id) U (min_active, max_trx_id)區(qū)間內(nèi)非活躍的事務(wù) U 當(dāng)前事務(wù)
      select讀取時(shí),通過版本鏈币绩,讀取出trx_id在readable_trx中且版本最新的記錄蜡秽,作為返回值府阀。由于讀取的要么是已提交事務(wù)的寫入,要么是當(dāng)前事務(wù)的寫入芽突,因此避免了臟讀试浙,然而由于每次select都會(huì)生成read view, 可讀取版本可能會(huì)不同,因此無法避免不可重復(fù)讀寞蚌。
  • repeatable read 級(jí)別下田巴, 在事務(wù)中的第一個(gè)select時(shí),去創(chuàng)建read view挟秤。確定當(dāng)前事務(wù)中select的可讀版本壹哺。之后每次select時(shí),都根據(jù)該read view 去讀取可讀且版本最新的數(shù)據(jù)艘刚。從而保證了該事務(wù)中的可重復(fù)讀管宵。

  • serializable級(jí)別下,串行化攀甚,那么就無法通過版本連來控制了箩朴。讀加共享鎖,寫加排他鎖秋度,讀寫互斥炸庞。

3. 當(dāng)前讀(鎖定讀)

在RC和RR隔離級(jí)別下,快照讀總是在當(dāng)前事務(wù)中先創(chuàng)建read view,然后讀出可讀版本的最新數(shù)據(jù)荚斯。然而在某些場(chǎng)景下埠居,我們希望的是,在當(dāng)前事務(wù)中要讀取數(shù)據(jù)時(shí)鲸拥,如果有其他事務(wù)正在寫入與查詢相關(guān)的數(shù)據(jù)拐格,我們先等他寫入完成,提交后獲取到讀取的機(jī)會(huì)刑赶,然后讀出寫入后的最新數(shù)據(jù)捏浊。這種模式下,快照讀就無能為力了撞叨。這是一個(gè)很典型的讀寫問題金踪,innodb為了解決這種問題,采用了讀寫鎖的解決辦法牵敷。

  • read uncommitted級(jí)別下胡岔, 讀寫均不互斥,假設(shè)事務(wù)b枷餐,更新某條記錄靶瘸,此時(shí)事務(wù)a 去select for update/ in share mode, 由于未作任何同步互斥, 此時(shí)事務(wù)a即可讀取到b對(duì)數(shù)據(jù)的寫入,如果事務(wù)b回滾怨咪,那么可能帶來很多負(fù)面的影響屋剑。
  • read committed級(jí)別下鎖定當(dāng)前記錄。臟讀是由于一個(gè)事務(wù)中對(duì)數(shù)據(jù)的寫入诗眨,在提交之前被另一個(gè)事務(wù)讀取到唉匾。那么解決思路就是寫入時(shí)對(duì)該數(shù)據(jù)加X鎖,讀取時(shí)根據(jù)需要加S鎖(select ... in share mode)或者X鎖(select ...for update)匠楚。也就是所謂的record lock巍膘。假設(shè)數(shù)據(jù)庫內(nèi)有非聚簇索引[1,3, 5, 5, 5, 7 ], 事務(wù)a在讀取索引為5的記錄時(shí)加record lock,此時(shí)另一個(gè)事務(wù)b想要修改索引為5的數(shù)據(jù)芋簿,發(fā)生阻塞峡懈。直到事務(wù)a提交事務(wù),釋放鎖之后益咬,事務(wù)b繼續(xù)執(zhí)行才能訪問逮诲。
    但是RC級(jí)別下帜平,無法解決幻讀的問題幽告,假設(shè)事務(wù)b是要插入一條索引為5的記錄,根據(jù)b+樹裆甩,它可以在(3,5), 5冗锁,(5,7)之間的任何位置進(jìn)行插入,此時(shí)僅僅鎖住了5這個(gè)點(diǎn)嗤栓,那么仍然可以在(3,5),(5,7)兩個(gè)區(qū)間的中間插入冻河。
image.png
事務(wù)a 事務(wù)b
begin; begin;
select count(1) from xx where sec_id = 5; (結(jié)果:3)
insert into xxx set ... sec_id =5
commit
select count(1) from xx where sec_id = 5; (結(jié)果:4)
...

repeatable read級(jí)別下,使用next-key lock的方式對(duì)索引加鎖茉帅,對(duì)非唯一索引而言叨叙,它不僅鎖住記錄本身(record lock),而且還對(duì)(3,5), (5,7)兩個(gè)區(qū)間加鎖(gap lock)堪澎。最終的效果就是擂错,在(3,7)區(qū)間內(nèi)的任何寫入樱蛤,都將被阻塞钮呀。對(duì)于唯一索引而言,只需要鎖住當(dāng)前記錄本身即可昨凡,因此next-key-lock降級(jí)為record lock爽醋。因此鎖定讀下的RR級(jí)別,避免了幻讀的問題便脊。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蚂四,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌遂赠,老刑警劉巖田度,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異解愤,居然都是意外死亡镇饺,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門送讲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奸笤,“玉大人,你說我怎么就攤上這事哼鬓〖嘤遥” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵异希,是天一觀的道長(zhǎng)健盒。 經(jīng)常有香客問我,道長(zhǎng)称簿,這世上最難降的妖魔是什么扣癣? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮憨降,結(jié)果婚禮上父虑,老公的妹妹穿的比我還像新娘。我一直安慰自己授药,他們只是感情好士嚎,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著悔叽,像睡著了一般莱衩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上娇澎,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天笨蚁,我揣著相機(jī)與錄音,去河邊找鬼九火。 笑死赚窃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的岔激。 我是一名探鬼主播勒极,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼虑鼎!你這毒婦竟也來了辱匿?” 一聲冷哼從身側(cè)響起键痛,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎匾七,沒想到半個(gè)月后絮短,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡昨忆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年丁频,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邑贴。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡席里,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拢驾,到底是詐尸還是另有隱情奖磁,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布繁疤,位于F島的核電站咖为,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏稠腊。R本人自食惡果不足惜躁染,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望麻养。 院中可真熱鬧褐啡,春花似錦、人聲如沸鳖昌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽许昨。三九已至,卻和暖如春褥赊,著一層夾襖步出監(jiān)牢的瞬間糕档,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國打工拌喉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留速那,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓尿背,卻偏偏與公主長(zhǎng)得像端仰,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子田藐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

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