MySQL事務(wù)隔離級(jí)別詳解

首先說(shuō)一下ACID四大特性:

四大特性

  • 原子性
    事務(wù)必須是原子工作單元昙读;對(duì)于其數(shù)據(jù)修改大脉,要么全都執(zhí)行,要么全都不執(zhí)行敬飒。通常痕鳍,與某個(gè)事務(wù)關(guān)聯(lián)的操作具有共同的目標(biāo)硫豆,并且是相互依賴的。如果系統(tǒng)只執(zhí)行這些操作的一個(gè)子集,則可能會(huì)破壞事務(wù)的總體目標(biāo)够庙。原子性消除了系統(tǒng)處理操作子集的可能性恭应。

  • 一致性
    事務(wù)在完成時(shí),必須使所有的數(shù)據(jù)都保持一致?tīng)顟B(tài)耘眨。在相關(guān)數(shù)據(jù)庫(kù)中,所有規(guī)則都必須應(yīng)用于事務(wù)的修改境肾,以保持所有數(shù)據(jù)的完整性剔难。事務(wù)結(jié)束時(shí),所有的內(nèi)部數(shù)據(jù)結(jié)構(gòu)(如 B 樹(shù)索引或雙向鏈表)都必須是正確的奥喻。某些維護(hù)一致性的責(zé)任由應(yīng)用程序開(kāi)發(fā)人員承擔(dān)偶宫,他們必須確保應(yīng)用程序已強(qiáng)制所有已知的完整性約束。例如环鲤,當(dāng)開(kāi)發(fā)用于轉(zhuǎn)帳的應(yīng)用程序時(shí)纯趋,應(yīng)避免在轉(zhuǎn)帳過(guò)程中任意移動(dòng)小數(shù)點(diǎn)。

  • 隔離性
    由并發(fā)事務(wù)所作的修改必須與任何其它并發(fā)事務(wù)所作的修改隔離冷离。事務(wù)查看數(shù)據(jù)時(shí)數(shù)據(jù)所處的狀態(tài)吵冒,要么是另一并發(fā)事務(wù)修改它之前的狀態(tài),要么是另一事務(wù)修改它之后的狀態(tài)西剥,事務(wù)不會(huì)查看中間狀態(tài)的數(shù)據(jù)痹栖。這稱為可串行性,因?yàn)樗軌蛑匦卵b載起始數(shù)據(jù)瞭空,并且重播一系列事務(wù)揪阿,以使數(shù)據(jù)結(jié)束時(shí)的狀態(tài)與原始事務(wù)執(zhí)行的狀態(tài)相同。當(dāng)事務(wù)可序列化時(shí)將獲得最高的隔離級(jí)別咆畏。在此級(jí)別上南捂,從一組可并行執(zhí)行的事務(wù)獲得的結(jié)果與通過(guò)連續(xù)運(yùn)行每個(gè)事務(wù)所獲得的結(jié)果相同。由于高度隔離會(huì)限制可并行執(zhí)行的事務(wù)數(shù)旧找,所以一些應(yīng)用程序降低隔離級(jí)別以換取更大的吞吐量溺健。

  • 持久性
    事務(wù)完成之后,它對(duì)于系統(tǒng)的影響是永久性的钦讳。該修改即使出現(xiàn)致命的系統(tǒng)故障也將一直保持矿瘦。

主要說(shuō)說(shuō)這個(gè)描述很抽象一致性,舉個(gè)例子:A向B轉(zhuǎn)賬愿卒,假設(shè)轉(zhuǎn)賬之前這兩個(gè)用戶的錢(qián)加起來(lái)總共是2000缚去,那么A向B轉(zhuǎn)賬之后,不管這兩個(gè)賬戶怎么轉(zhuǎn)琼开,A用戶的錢(qián)和B用戶的錢(qián)加起來(lái)的總額還是2000易结,這個(gè)就是事務(wù)的一致性。

四種隔離級(jí)別

  • Read Uncommitted(讀取未提交內(nèi)容)
    在該隔離級(jí)別,所有事務(wù)都可以看到其他未提交事務(wù)的執(zhí)行結(jié)果搞动。本隔離級(jí)別很少用于實(shí)際應(yīng)用躏精,因?yàn)樗男阅芤膊槐绕渌?jí)別好多少。讀取未提交的數(shù)據(jù)鹦肿,也被稱之為臟讀(Dirty Read)矗烛。

  • Read Committed(讀取提交內(nèi)容)
    這是大多數(shù)數(shù)據(jù)庫(kù)系統(tǒng)的默認(rèn)隔離級(jí)別(但不是MySQL默認(rèn)的)。它滿足了隔離的簡(jiǎn)單定義:一個(gè)事務(wù)只能看見(jiàn)已經(jīng)提交事務(wù)所做的改變箩溃。這種隔離級(jí)別 也支持所謂的不可重復(fù)讀(Nonrepeatable Read)瞭吃,因?yàn)橥皇聞?wù)的其他實(shí)例在該實(shí)例處理其間可能會(huì)有新的commit,所以同一select可能返回不同結(jié)果涣旨。

  • Repeatable Read(可重讀)
    這是MySQL的默認(rèn)事務(wù)隔離級(jí)別歪架,它確保同一事務(wù)的多個(gè)實(shí)例在并發(fā)讀取數(shù)據(jù)時(shí),會(huì)看到同樣的數(shù)據(jù)行霹陡。不過(guò)理論上和蚪,這會(huì)導(dǎo)致另一個(gè)棘手的問(wèn)題:幻讀 (Phantom Read)。簡(jiǎn)單的說(shuō)烹棉,幻讀指當(dāng)用戶讀取某一范圍的數(shù)據(jù)行時(shí)攒霹,另一個(gè)事務(wù)又在該范圍內(nèi)插入了新行,當(dāng)用戶再讀取該范圍的數(shù)據(jù)行時(shí)峦耘,會(huì)發(fā)現(xiàn)有新的“幻影” 行剔蹋。InnoDB和Falcon存儲(chǔ)引擎通過(guò)多版本并發(fā)控制(MVCC,Multiversion Concurrency Control)機(jī)制解決了該問(wèn)題辅髓。

  • Serializable(可串行化)
    這是最高的隔離級(jí)別泣崩,它通過(guò)強(qiáng)制事務(wù)排序,使之不可能相互沖突洛口,從而解決幻讀問(wèn)題矫付。簡(jiǎn)言之,它是在每個(gè)讀的數(shù)據(jù)行上加上共享鎖第焰。在這個(gè)級(jí)別买优,可能導(dǎo)致大量的超時(shí)現(xiàn)象和鎖競(jìng)爭(zhēng)。這四種隔離級(jí)別采取不同的鎖類型來(lái)實(shí)現(xiàn)挺举,若讀取的是同一個(gè)數(shù)據(jù)的話杀赢,就容易發(fā)生問(wèn)題。例如:

  1. 臟讀(Drity Read):某個(gè)事務(wù)已更新一份數(shù)據(jù)湘纵,另一個(gè)事務(wù)在此時(shí)讀取了同一份數(shù)據(jù)脂崔,由于某些原因,前一個(gè)RollBack了操作梧喷,則后一個(gè)事務(wù)所讀取的數(shù)據(jù)就會(huì)是不正確的砌左。
  2. 不可重復(fù)讀(Non-repeatable read):在一個(gè)事務(wù)的兩次查詢之中數(shù)據(jù)不一致脖咐,這可能是兩次查詢過(guò)程中間插入了一個(gè)事務(wù)更新的原有的數(shù)據(jù)。
  3. 幻讀(Phantom Read):在一個(gè)事務(wù)的兩次查詢中數(shù)據(jù)筆數(shù)不一致汇歹,例如有一個(gè)事務(wù)查詢了幾列(Row)數(shù)據(jù)屁擅,而另一個(gè)事務(wù)卻在此時(shí)插入了新的幾列數(shù)據(jù),先前的事務(wù)在接下來(lái)的查詢中产弹,就會(huì)發(fā)現(xiàn)有幾列數(shù)據(jù)是它先前所沒(méi)有的派歌。
  4. 在MySQL中,實(shí)現(xiàn)了這四種隔離級(jí)別取视,分別有可能產(chǎn)生問(wèn)題如下所示:
    [圖片上傳失敗...(image-65048f-1543570309304)]

然后是關(guān)于數(shù)據(jù)庫(kù)的各種鎖的總結(jié)

  1. 共享鎖(又稱讀鎖)硝皂、排它鎖(又稱寫(xiě)鎖)
    InnoDB引擎的鎖機(jī)制:InnoDB支持事務(wù),支持行鎖和表鎖用的比較多作谭,Myisam不支持事務(wù),只支持表鎖奄毡。
    共享鎖(S):允許一個(gè)事務(wù)去讀一行折欠,阻止其他事務(wù)獲得相同數(shù)據(jù)集的排他鎖。
    排他鎖(X):允許獲得排他鎖的事務(wù)更新數(shù)據(jù)吼过,阻止其他事務(wù)取得相同數(shù)據(jù)集的共享讀鎖和排他寫(xiě)鎖锐秦。
    意向共享鎖(IS):事務(wù)打算給數(shù)據(jù)行加行共享鎖,事務(wù)在給一個(gè)數(shù)據(jù)行加共享鎖前必須先取得該表的IS鎖盗忱。
    意向排他鎖(IX):事務(wù)打算給數(shù)據(jù)行加行排他鎖酱床,事務(wù)在給一個(gè)數(shù)據(jù)行加排他鎖前必須先取得該表的IX鎖
    說(shuō)明:
    1)共享鎖和排他鎖都是行鎖,意向鎖都是表鎖趟佃,應(yīng)用中我們只會(huì)使用到共享鎖和排他鎖扇谣,意向鎖是mysql內(nèi)部使用的,不需要用戶干預(yù)闲昭。
    2)對(duì)于UPDATE罐寨、DELETE和INSERT語(yǔ)句,InnoDB會(huì)自動(dòng)給涉及數(shù)據(jù)集加排他鎖(X)序矩;對(duì)于普通SELECT語(yǔ)句鸯绿,InnoDB不會(huì)加任何鎖,事務(wù)可以通過(guò)以下語(yǔ)句顯示給記錄集加共享鎖或排他鎖簸淀。
    共享鎖(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE瓶蝴。
    排他鎖(X):SELECT * FROM table_name WHERE ... FOR UPDATE。
    對(duì)于鎖定行記錄后需要進(jìn)行更新操作的應(yīng)用租幕,應(yīng)該使用Select...For update 方式舷手,獲取排它鎖。(用共享鎖令蛉,在讀了之后再寫(xiě)會(huì)阻塞聚霜,會(huì)導(dǎo)致死鎖)
    這里說(shuō)說(shuō)Myisam:MyISAM在執(zhí)行查詢語(yǔ)句(SELECT)前狡恬,會(huì)自動(dòng)給涉及的所有表加讀鎖,在執(zhí)行更新操作(UPDATE蝎宇、DELETE弟劲、INSERT等)前,會(huì)自動(dòng)給涉及的表加寫(xiě)鎖姥芥。
    3)InnoDB行鎖是通過(guò)給索引上的索引項(xiàng)加鎖來(lái)實(shí)現(xiàn)的兔乞,因此InnoDB這種行鎖實(shí)現(xiàn)特點(diǎn)意味著:只有通過(guò)索引條件檢索數(shù)據(jù),InnoDB才使用行級(jí)鎖凉唐,否則庸追,InnoDB將使用表鎖!

  2. 樂(lè)觀鎖台囱、悲觀鎖
    悲觀鎖:悲觀鎖淡溯,正如其名,它指的是對(duì)數(shù)據(jù)被外界(包括本系統(tǒng)當(dāng)前的其他事務(wù)簿训,以及來(lái)自外部系統(tǒng)的事務(wù)處理)修改持保守態(tài)度咱娶,因此,在整個(gè)數(shù)據(jù)處理過(guò)程中强品,將數(shù)據(jù)處于鎖定狀態(tài)膘侮。悲觀鎖的實(shí)現(xiàn),往往依靠數(shù)據(jù)庫(kù)提供的鎖機(jī)制(也只有數(shù)據(jù)庫(kù)層提供的鎖機(jī)制才能真正保證數(shù)據(jù)訪問(wèn)的排他性的榛,否則琼了,即使在本系統(tǒng)中實(shí)現(xiàn)了加鎖機(jī)制,也無(wú)法保證外部系統(tǒng)不會(huì)修改數(shù)據(jù))
    1)使用悲觀鎖夫晌,我們必須關(guān)閉mysql數(shù)據(jù)庫(kù)的自動(dòng)提交屬性雕薪,采用手動(dòng)提交事務(wù)的方式,因?yàn)镸ySQL默認(rèn)使用autocommit模式慷丽,也就是說(shuō)蹦哼,當(dāng)你執(zhí)行一個(gè)更新操作后,MySQL會(huì)立刻將結(jié)果進(jìn)行提交要糊。
    2)需要注意的是纲熏,在事務(wù)中,只有SELECT ... FOR UPDATE 或LOCK IN SHARE MODE 同一筆數(shù)據(jù)時(shí)會(huì)等待其它事務(wù)結(jié)束后才執(zhí)行锄俄,一般SELECT ... 則不受此影響局劲。對(duì)于UPDATE、DELETE和INSERT語(yǔ)句奶赠,InnoDB會(huì)自動(dòng)給涉及數(shù)據(jù)集加排他鎖(X)鱼填。
    3)補(bǔ)充:MySQL select…for update的Row Lock與Table Lock
    使用select…for update會(huì)把數(shù)據(jù)給鎖住,不過(guò)我們需要注意一些鎖的級(jí)別毅戈,MySQL InnoDB默認(rèn)Row-Level Lock苹丸,所以只有「明確」地指定主鍵(或有索引的地方)愤惰,MySQL 才會(huì)執(zhí)行Row lock (只鎖住被選取的數(shù)據(jù)) ,否則MySQL 將會(huì)執(zhí)行Table Lock (將整個(gè)數(shù)據(jù)表單給鎖住)赘理。
    樂(lè)觀鎖:樂(lè)觀鎖( Optimistic Locking ) 相對(duì)悲觀鎖而言宦言,樂(lè)觀鎖假設(shè)認(rèn)為數(shù)據(jù)一般情況下不會(huì)造成沖突,所以在數(shù)據(jù)進(jìn)行提交更新的時(shí)候商模,才會(huì)正式對(duì)數(shù)據(jù)的沖突與否進(jìn)行檢測(cè)奠旺,如果發(fā)現(xiàn)沖突了,則讓返回用戶錯(cuò)誤的信息施流,讓用戶決定如何去做(一般是回滾事務(wù))响疚。那么我們?nèi)绾螌?shí)現(xiàn)樂(lè)觀鎖呢,一般來(lái)說(shuō)有以下2種方式:
    1).使用數(shù)據(jù)版本(Version)記錄機(jī)制實(shí)現(xiàn)瞪醋,這是樂(lè)觀鎖最常用的一種實(shí)現(xiàn)方式忿晕。何謂數(shù)據(jù)版本?即為數(shù)據(jù)增加一個(gè)版本標(biāo)識(shí)银受,一般是通過(guò)為數(shù)據(jù)庫(kù)表增加一個(gè)數(shù)字類型的 “version” 字段來(lái)實(shí)現(xiàn)杏糙。當(dāng)讀取數(shù)據(jù)時(shí),將version字段的值一同讀出蚓土,數(shù)據(jù)每更新一次,對(duì)此version值加一赖淤。當(dāng)我們提交更新的時(shí)候蜀漆,判斷數(shù)據(jù)庫(kù)表對(duì)應(yīng)記錄的當(dāng)前版本信息與第一次取出來(lái)的version值進(jìn)行比對(duì),如果數(shù)據(jù)庫(kù)表當(dāng)前版本號(hào)與第一次取出來(lái)的version值相等咱旱,則予以更新确丢,否則認(rèn)為是過(guò)期數(shù)據(jù)。
    2).樂(lè)觀鎖定的第二種實(shí)現(xiàn)方式和第一種差不多吐限,同樣是在需要樂(lè)觀鎖控制的table中增加一個(gè)字段鲜侥,名稱無(wú)所謂,字段類型使用時(shí)間戳(timestamp), 和上面的version類似诸典,也是在更新提交的時(shí)候檢查當(dāng)前數(shù)據(jù)庫(kù)中數(shù)據(jù)的時(shí)間戳和自己更新前取到的時(shí)間戳進(jìn)行對(duì)比描函,如果一致則OK,否則就是版本沖突狐粱。
    總結(jié):兩種鎖各有優(yōu)缺點(diǎn)舀寓,不可認(rèn)為一種好于另一種,像樂(lè)觀鎖適用于寫(xiě)比較少的情況下肌蜻,即沖突真的很少發(fā)生的時(shí)候互墓,這樣可以省去了鎖的開(kāi)銷,加大了系統(tǒng)的整個(gè)吞吐量蒋搜。但如果經(jīng)常產(chǎn)生沖突篡撵,上層應(yīng)用會(huì)不斷的進(jìn)行retry判莉,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適育谬。
    另外券盅,高并發(fā)情況下個(gè)人認(rèn)為樂(lè)觀鎖要好于悲觀鎖,因?yàn)楸^鎖的機(jī)制使得各個(gè)線程等待時(shí)間過(guò)長(zhǎng)斑司,極其影響效率渗饮,樂(lè)觀鎖可以在一定程度上提高并發(fā)度。

  3. 表鎖宿刮、行鎖
    表級(jí)鎖(table-level locking):MyISAM和MEMORY存儲(chǔ)引擎
    行級(jí)鎖(row-level locking) :InnoDB存儲(chǔ)引擎
    頁(yè)面鎖(page-level-locking):BDB存儲(chǔ)引擎
    表級(jí)鎖:開(kāi)銷小互站,加鎖快;不會(huì)出現(xiàn)死鎖;鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低僵缺。
    行級(jí)鎖:開(kāi)銷大胡桃,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高磕潮。
    頁(yè)面鎖:開(kāi)銷和加鎖時(shí)間界于表鎖和行鎖之間;會(huì)出現(xiàn)死鎖;鎖定粒度界于表鎖和行鎖之間翠胰,并發(fā)度一般。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末自脯,一起剝皮案震驚了整個(gè)濱河市之景,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌膏潮,老刑警劉巖锻狗,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異焕参,居然都是意外死亡轻纪,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)叠纷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)刻帚,“玉大人,你說(shuō)我怎么就攤上這事涩嚣〕缰冢” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵缓艳,是天一觀的道長(zhǎng)校摩。 經(jīng)常有香客問(wèn)我,道長(zhǎng)阶淘,這世上最難降的妖魔是什么衙吩? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮溪窒,結(jié)果婚禮上坤塞,老公的妹妹穿的比我還像新娘冯勉。我一直安慰自己,他們只是感情好摹芙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布灼狰。 她就那樣靜靜地躺著,像睡著了一般浮禾。 火紅的嫁衣襯著肌膚如雪交胚。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,301評(píng)論 1 301
  • 那天盈电,我揣著相機(jī)與錄音蝴簇,去河邊找鬼。 笑死匆帚,一個(gè)胖子當(dāng)著我的面吹牛熬词,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播吸重,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼互拾,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了嚎幸?” 一聲冷哼從身側(cè)響起颜矿,我...
    開(kāi)封第一講書(shū)人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嫉晶,沒(méi)想到半個(gè)月后或衡,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡车遂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了斯辰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舶担。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖彬呻,靈堂內(nèi)的尸體忽然破棺而出衣陶,到底是詐尸還是另有隱情,我是刑警寧澤闸氮,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布剪况,位于F島的核電站,受9級(jí)特大地震影響蒲跨,放射性物質(zhì)發(fā)生泄漏译断。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一或悲、第九天 我趴在偏房一處隱蔽的房頂上張望孙咪。 院中可真熱鬧堪唐,春花似錦、人聲如沸翎蹈。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)荤堪。三九已至合陵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間澄阳,已是汗流浹背拥知。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寇荧,地道東北人举庶。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像揩抡,于是被迫代替她去往敵國(guó)和親户侥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

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