MySQL的隔離級別和鎖的關系

一、事務的四大特性(ACID)

如果一個數(shù)據(jù)庫聲稱支持事務的操作,那么該數(shù)據(jù)庫必須要具備以下四個特性:

1.1 原子性(Atomicity)

原子性是指事務包含的所有操作要么全部成功俐筋,要么全部失敗回滾知纷,因此事務的操作如果成功就必須要完全應用到數(shù)據(jù)庫,如果操作失敗則不能對數(shù)據(jù)庫有任何影響。

1.2 一致性(Consistency)

一致性是指事務必須使數(shù)據(jù)庫從一個一致性狀態(tài)變換到另一個一致性狀態(tài)互站,也就是說一個事務執(zhí)行之前和執(zhí)行之后都必須處于一致性狀態(tài)。拿轉(zhuǎn)賬來說僵缺,假設用戶A和用戶B兩者的錢加起來一共是5000胡桃,那么不管A和B之間如何轉(zhuǎn)賬,轉(zhuǎn)幾次賬磕潮,事務結(jié)束后兩個用戶的錢相加起來應該還得是5000翠胰,這就是事務的一致性。

1.3 隔離性(Isolation)

隔離性是當多個用戶并發(fā)訪問數(shù)據(jù)庫時自脯,比如操作同一張表時之景,數(shù)據(jù)庫為每一個用戶開啟的事務,不能被其他事務的操作所干擾膏潮,多個并發(fā)事務之間要相互隔離锻狗。即要達到這么一種效果:對于任意兩個并發(fā)的事務T1和T2,在事務T1看來焕参,T2要么在T1開始之前就已經(jīng)結(jié)束轻纪,要么在T1結(jié)束之后才開始,這樣每個事務都感覺不到有其他事務在并發(fā)地執(zhí)行龟糕。

1.4 持久性(Durability)

持久性是指一個事務一旦被提交了桐磁,那么對數(shù)據(jù)庫中的數(shù)據(jù)的改變就是永久性的悔耘,即便是在數(shù)據(jù)庫系統(tǒng)遇到故障的情況下也不會丟失提交事務的操作讲岁。例如我們在使用JDBC操作數(shù)據(jù)庫時,在提交事務方法后衬以,提示用戶事務操作完成缓艳,當我們程序執(zhí)行完成直到看到提示后,就可以認定事務以及正確提交看峻,即使這時候數(shù)據(jù)庫出現(xiàn)了問題阶淘,也必須要將我們的事務完全執(zhí)行完成,否則就會造成我們看到提示事務處理完畢互妓,但是數(shù)據(jù)庫因為故障而沒有執(zhí)行事務的重大錯誤溪窒。

二、數(shù)據(jù)庫隔離級別

數(shù)據(jù)庫事務的隔離級別有4個冯勉。由低到高依次為Read uncommitted澈蚌、Read committed、Repeatable read灼狰、Serializable宛瞄。這四個級別能夠逐個解決臟讀、不可反復讀交胚、幻讀這幾類問題份汗。MySQL設置的隔離級別默認是Repeatable Read可反復讀級別

注意:MySQL 中默認的事務隔離級別就是 Repeatable Read可反復讀級別盈电,但是它通過 Next-Key 鎖也能夠在某種程度上解決幻讀的問題。

事務級別 臟讀 不可反復讀 幻讀
Read uncommitted
Read committed ×
Repeatable read × ×
Serializable × × ×

√: 可能出現(xiàn) ×: 不會出現(xiàn)

注意:我們討論隔離級別的場景杯活,主要是在多個事務并發(fā)的情況下匆帚。因此,接下來的解說都環(huán)繞事務并發(fā)旁钧。

2.1 Read uncommitted 讀未提交

Read uncommitted是限制性最弱的隔離級別卷扮。由于該級別忽略其它事務放置的鎖。使用READ UNCOMMITTED級別運行的事務均践,能夠讀取尚未由其它事務提交的改動后的數(shù)據(jù)值晤锹,這些行為稱為“臟”讀。我們所說的臟讀彤委,兩個并發(fā)的事務鞭铆,“事務A:領導給singo發(fā)工資”、“事務B:singo查詢工資賬戶”焦影,事務B讀取了事務A尚未提交的數(shù)據(jù)车遂。比方,事務1改動一行斯辰,事務2在事務1提交之前讀取了這一行舶担。假設事務1回滾,事務2就讀取了一行沒有提交的數(shù)據(jù)彬呻。這種數(shù)據(jù)我們覺得是不存在的衣陶。

補充:
比如事務B讀取了事務A 更改但未提交的數(shù)據(jù)D。有人會問闸氮,這會有什么問題嗎剪况?如果事務A沒有再修改數(shù)據(jù)D,并且事務也沒有出錯正常提交了蒲跨,其實事務B讀取了數(shù)據(jù)D沒有什么問題译断。但如果事務B讀取數(shù)據(jù)D后,事務A又改了數(shù)據(jù)D呢或悲?甚至如果事務A失敗回滾了呢孙咪?那么事務B讀的數(shù)據(jù)D就是錯的值,如果事務B對這個數(shù)據(jù)D再做修改巡语,肯定就是錯的翎蹈。

2.2 Read committed 讀提交

該級別通過指定語句不能讀取其它事務已改動可是尚未提交的數(shù)據(jù)值。禁止運行臟讀捌臊。在當前事務中的各個語句運行之間杨蛋,其它事務仍能夠改動、插入或刪除數(shù)據(jù)。從而產(chǎn)生無法反復的讀操作逞力∈锕眩或“影子”數(shù)據(jù)。比方寇荧,事務1讀取了一行举庶。事務2改動或者刪除這一行而且提交。假設事務1想再一次讀取這一行揩抡,它將獲得改動后的數(shù)據(jù)或者發(fā)現(xiàn)這一樣已經(jīng)被刪除户侥。因此事務的第二次讀取結(jié)果與第一次讀取結(jié)果不同,因此也叫不可反復讀峦嗤。
大多數(shù)數(shù)據(jù)庫的默認級別就是Read committed蕊唐。比方Sql Server , Oracle。怎樣解決不可反復讀這一問題烁设。請看下一個隔離級別替梨。

2.3 Repeatable read 反復讀

Repeatable read是比Read committed限制性更強的隔離級別。
該級別包含Read committed装黑,而且另外指定了在當前事務提交之前副瀑。其它不論什么事務均不能夠改動或刪除當前事務已讀取的數(shù)據(jù)。并發(fā)性低于Read committed恋谭。由于已讀數(shù)據(jù)的共享鎖在整個事務期間持有糠睡,而不是在每一個語句結(jié)束時釋放。

這個隔離級別僅僅是說疚颊,不可以改動和刪除狈孔,可是并沒有強制不能插入新的滿足條件查詢的數(shù)據(jù)行。此可以得出結(jié)論:Read committed隔離級別保證了在同樣的查詢條件下串稀,同一個事務中的兩個查詢除抛。第二次讀取的內(nèi)容肯定包含第一次讀到的內(nèi)容。

反復讀與幻讀

反復讀是為了保證在一個事務中母截,相同查詢條件下讀取的數(shù)據(jù)值不發(fā)生改變,可是不能保證下次相同條件查詢橄教。結(jié)果記錄數(shù)不會添加清寇。

幻讀就是為了解決問題而存在的,他將這個查詢范圍都加鎖了护蝶。所以就不能再往這個范圍內(nèi)插入數(shù)據(jù)华烟。這就是SERIALIZABLE 隔離級別做的事情。

2.4 Serializable 序列化

Serializable 是限制性最強的隔離級別持灰,由于該級別鎖定整個范圍的鍵盔夜。并一直持有鎖,直到事務完畢。該級別包含REPEATABLE READ喂链。并添加了在事務完畢之前返十,其它事務不能向事務已讀取的范圍插入新行的限制。比方椭微,事務1讀取了一系列滿足搜索條件的行洞坑。事務2在運行SQL statement產(chǎn)生一行或者多行滿足事務1搜索條件的行時會沖突。則事務2回滾蝇率。這時事務1再次讀取了一系列滿足同樣搜索條件的行迟杂。第二次讀取的結(jié)果和第一次讀取的結(jié)果同樣。

三本慕、鎖

3.1 一次封鎖or兩段鎖排拷?

由于有大量的并發(fā)訪問,為了預防死鎖锅尘。一般應用中推薦使用一次封鎖法攻泼。就是在方法的開始階段。已經(jīng)預先知道會用到哪些數(shù)據(jù)鉴象,然后所有鎖住忙菠,在方法執(zhí)行之后,再所有解鎖纺弊。
這樣的方式能夠有效的避免循環(huán)死鎖牛欢,但在數(shù)據(jù)庫中卻不適用,由于在事務開始階段淆游,數(shù)據(jù)庫并不知道會用到哪些數(shù)據(jù)傍睹。數(shù)據(jù)庫遵循的是兩段鎖協(xié)議,將事務分成兩個階段犹菱,加鎖階段和解鎖階段(所以叫兩段鎖)

  • 加鎖階段:在該階段能夠進行加鎖操作拾稳。在對不論什么數(shù)據(jù)進行讀操作之前要申請并獲得S鎖(共享鎖,其他事務能夠繼續(xù)加共享鎖腊脱,但不能加排它鎖)访得,在進行寫操作之前要申請并獲得X鎖(排它鎖,其他事務不能再獲得不論什么鎖)陕凹。加鎖不成功悍抑,則事務進入等待狀態(tài),直到加鎖成功才繼續(xù)運行杜耙。

  • 解鎖階段:當事務釋放了一個封鎖以后搜骡,事務進入解鎖階段。在該階段僅僅能進行解鎖操作不能再進行加鎖操作佑女。

事務 加鎖/解鎖處理
begin记靡。
insert into test ..... 加insert相應的鎖
update test set... 加update相應的鎖
delete from test .... 加delete相應的鎖
commit; 事務提交時谈竿,同一時候釋放insert、update摸吠、delete相應的鎖
這樣的方式盡管無法避免死鎖空凸。可是兩段鎖協(xié)議能夠保證事務的并發(fā)調(diào)度是串行化(串行化非常重要蜕便,尤其是在數(shù)據(jù)恢復和備份的時候)的劫恒。

3.2不可反復讀和幻讀的差別

非常多人easy搞混不可反復讀和幻讀,確實這兩者有些相似轿腺。但不可反復讀重點在于update和delete两嘴。而幻讀的重點在于insert。

假設使用鎖機制來實現(xiàn)這兩種隔離級別族壳。在可反復讀中,該sql第一次讀取到數(shù)據(jù)后贰您。就將這些數(shù)據(jù)加鎖锦亦,其他事務無法改動這些數(shù)據(jù)杠园。就能夠?qū)崿F(xiàn)可反復讀了抛蚁。但這樣的方法卻無法鎖住insert的數(shù)據(jù)瞧甩。所以當事務A先前讀取了數(shù)據(jù)肚逸,或者改動了所有數(shù)據(jù)吼虎,事務B還是能夠insert數(shù)據(jù)提交苍鲜,這時事務A就會發(fā)現(xiàn)莫名其妙多了一條之前沒有的數(shù)據(jù)混滔。這就是幻讀坯屿。不能通過行鎖來避免领跛。須要Serializable隔離級別 吠昭。讀用讀鎖矢棚,寫用寫鎖蘑拯,讀鎖和寫鎖相互排斥申窘,這么做能夠有效的避免幻讀剃法、不可反復讀、臟讀等問題恩脂,但會極大的減少數(shù)據(jù)庫的并發(fā)能力俩块。

所以說不可反復讀和幻讀最大的差別浓领,就在于怎樣通過鎖機制來解決他們產(chǎn)生的問題玉凯。
上文說的,是使用悲觀鎖機制來處理這兩種問題联贩,可是MySQL漫仆、ORACLE、PostgreSQL等成熟的數(shù)據(jù)庫泪幌。出于性能考慮盲厌,都是使用了以樂觀鎖為理論基礎的MVCC(多版本號并發(fā)控制)來避免這兩種問題署照。

3.3 悲觀鎖和樂觀鎖

悲觀鎖
正如其名,它指的是對數(shù)據(jù)被外界(包含本系統(tǒng)當前的其它事務吗浩,以及來自外部系統(tǒng)的事務處理)改動持保守態(tài)度建芙。因此,在整個數(shù)據(jù)處理過程中懂扼,將數(shù)據(jù)處于鎖定狀態(tài)禁荸。悲觀鎖的實現(xiàn)。往往依靠數(shù)據(jù)庫提供的鎖機制(也僅僅有數(shù)據(jù)庫層提供的鎖機制才干真正保證數(shù)據(jù)訪問的排他性阀湿,否則赶熟,即使在本系統(tǒng)中實現(xiàn)了加鎖機制,也無法保證外部系統(tǒng)不會改動數(shù)據(jù))炕倘。在悲觀鎖的情況下钧大,為了保證事務的隔離性,就須要一致性鎖定讀罩旋。讀取數(shù)據(jù)時給加鎖啊央,其他事務無法改動這些數(shù)據(jù)。改動刪除數(shù)據(jù)時也要加鎖涨醋,其他事務無法讀取這些數(shù)據(jù)瓜饥。

樂觀鎖
相對悲觀鎖而言,樂觀鎖機制採取了更加寬松的加鎖機制浴骂。悲觀鎖大多數(shù)情況下依靠數(shù)據(jù)庫的鎖機制實現(xiàn)乓土,以保證操作最大程度的獨占性。但隨之而來的就是數(shù)據(jù)庫性能的大量開銷溯警。特別是對長事務而言趣苏,這種開銷往往無法承受。而樂觀鎖機制在一定程度上攻克了這個問題梯轻。樂觀鎖食磕,大多是基于數(shù)據(jù)版本號( Version )記錄機制實現(xiàn)。何謂數(shù)據(jù)版本號喳挑?即為數(shù)據(jù)添加一個版本號標識彬伦,在基于數(shù)據(jù)庫表的版本號解決方式中,通常是通過為數(shù)據(jù)庫表添加一個“version” 字段來實現(xiàn)伊诵。讀取出數(shù)據(jù)時单绑,將此版本號號一同讀出,之后更新時曹宴,對此版本號號加一搂橙。

此時。將提交數(shù)據(jù)的版本號數(shù)據(jù)與數(shù)據(jù)庫表相應記錄的當前版本號信息進行比對笛坦,假設提交的數(shù)據(jù)版本號號大于數(shù)據(jù)庫表當前版本號號份氧,則予以更新唯袄。否則覺得是過期數(shù)據(jù)弯屈。

要說明的是蜗帜,MVCC的實現(xiàn)沒有固定的規(guī)范,每一個數(shù)據(jù)庫都會有不同的實現(xiàn)方式资厉,這里討論的是InnoDB的MVCC厅缺。

四、MVCC在MySQL的InnoDB中的實現(xiàn)

在InnoDB中宴偿,會在每行數(shù)據(jù)后加入兩個額外的隱藏的值來實現(xiàn)MVCC湘捎,這兩個值一個記錄這行數(shù)據(jù)何時被創(chuàng)建,另外一個記錄這行數(shù)據(jù)何時過期(或者被刪除)窄刘。 在實際操作中窥妇。存儲的并非時間,而是事務的版本娩践,每開啟一個新事務活翩,事務的版本就會遞增。 在可重讀Repeatable reads事務隔離級別下:
SELECT時翻伺。讀取創(chuàng)建版本<=當前事務版本材泄。刪除版本為空或>當前事務版本。
INSERT時吨岭,保存當前事務版本為行的創(chuàng)建版本
DELETE時拉宗,保存當前事務版本為行的刪除版本
UPDATE時,插入一條新紀錄辣辫。保存當前事務版本為行創(chuàng)建版本旦事,同一時候保存當前事務版本到原來刪除的行

通過MVCC,盡管每行記錄都須要額外的存儲空間急灭,很多其它的行檢查工作以及一些額外的維護工作姐浮。但能夠降低鎖的使用,大多數(shù)讀操作都不用加鎖化戳,讀數(shù)據(jù)操作非常easy单料,性能非常好,而且也能保證僅僅會讀取到符合標準的行点楼。也僅僅鎖住必要行扫尖。

我們無論從數(shù)據(jù)庫方面的教課書中學到。還是從網(wǎng)絡上看到掠廓,大都是上文中事務的四種隔離級別這一模塊列出的意思换怖,RR級別是可反復讀的,但無法解決幻讀蟀瞧。而僅僅有在Serializable級別才干解決幻讀沉颂。

轉(zhuǎn)自:MySql的隔離級別和鎖的關系

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末条摸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子铸屉,更是在濱河造成了極大的恐慌钉蒲,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件彻坛,死亡現(xiàn)場離奇詭異顷啼,居然都是意外死亡,警方通過查閱死者的電腦和手機昌屉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門钙蒙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嘱支,“玉大人愿吹,你說我怎么就攤上這事『莨” “怎么了竞帽?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵扛施,是天一觀的道長。 經(jīng)常有香客問我抢呆,道長煮嫌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任抱虐,我火速辦了婚禮昌阿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘恳邀。我一直安慰自己懦冰,他們只是感情好,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布谣沸。 她就那樣靜靜地躺著刷钢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乳附。 梳的紋絲不亂的頭發(fā)上内地,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天,我揣著相機與錄音赋除,去河邊找鬼阱缓。 笑死,一個胖子當著我的面吹牛举农,可吹牛的內(nèi)容都是我干的荆针。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼航背!你這毒婦竟也來了喉悴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤玖媚,失蹤者是張志新(化名)和其女友劉穎箕肃,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體最盅,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡突雪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了涡贱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡惹想,死狀恐怖问词,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嘀粱,我是刑警寧澤激挪,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站锋叨,受9級特大地震影響垄分,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜娃磺,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一薄湿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧偷卧,春花似錦豺瘤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至晌梨,卻和暖如春桥嗤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仔蝌。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工泛领, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人掌逛。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓师逸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子篓像,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354