數(shù)據(jù)庫事務(wù)淺析

ACID

一個數(shù)據(jù)庫事務(wù)通常包含了一個序列的對數(shù)據(jù)庫的讀/寫操作。它的存在包含有以下兩個目的:

  1. 為數(shù)據(jù)庫操作序列提供了一個從失敗中恢復(fù)到正常狀態(tài)的方法氮发,同時提供了數(shù)據(jù)庫即使在異常狀態(tài)下仍能保持一致性的方法渴肉。
  2. 當(dāng)多個應(yīng)用程序在并發(fā)訪問數(shù)據(jù)庫時,可以在這些應(yīng)用程序之間提供一個隔離方法爽冕,以防止彼此的操作互相干擾仇祭。

上面對數(shù)據(jù)庫事務(wù)的定義摘自維基百科。先不用著急的去理解這個定義的具體含義颈畸,我們從事務(wù)的四個特性來逐步了解什么是事務(wù)乌奇。

數(shù)據(jù)庫事務(wù)擁有以下四個特性没讲,習(xí)慣上被稱之為ACID特性。

  1. 原子性(Atomicity):事務(wù)作為一個整體被執(zhí)行礁苗,包含在其中的對數(shù)據(jù)庫的操作要么全部被執(zhí)行爬凑,要么都不執(zhí)行。

  2. 一致性(Consistency):事務(wù)應(yīng)確保數(shù)據(jù)庫的狀態(tài)從一個一致狀態(tài)轉(zhuǎn)變?yōu)榱硪粋€一致狀態(tài)试伙。一致狀態(tài)的含義是數(shù)據(jù)庫中的數(shù)據(jù)應(yīng)滿足完整性約束嘁信。

  3. 隔離性(Isolation):多個事務(wù)并發(fā)執(zhí)行時,一個事務(wù)的執(zhí)行不應(yīng)影響其他事務(wù)的執(zhí)行疏叨。

  4. 持久性(Durability):已被提交的事務(wù)對數(shù)據(jù)庫的修改應(yīng)該永久保存在數(shù)據(jù)庫中潘靖。

用一個轉(zhuǎn)賬的例子來解釋,這個例子被用爛了蚤蔓,卻很經(jīng)典:

從A賬戶向B賬戶轉(zhuǎn)賬100元卦溢,可能分為以下幾個步驟:

  1. 讀取A賬戶,將A賬戶余額減100

  2. A 賬戶余額寫回數(shù)據(jù)庫

  3. 讀取B賬戶秀又,將B賬戶余額加100

  4. B賬戶余額寫回數(shù)據(jù)庫

  • 一致性

    什么叫數(shù)據(jù)一致性既绕?通常是由我們自己來定義的。在上面的場景中涮坐,就是在轉(zhuǎn)賬的前后,A賬戶和B賬戶的總額保持不變誓军。

    再舉一個例子袱讹,之前做過一個版本管理系統(tǒng),用戶發(fā)布一個的版本(上傳若干附件)昵时,版本記錄表就要插入一行記錄捷雕,相對應(yīng)的,附件表也要插入若干的記錄(一對多的關(guān)系)壹甥。對于這兩個表的操作救巷,要么全做,要么不做句柠,如果附件表插入了記錄浦译,而版本記錄表沒有操作,不符合一致性定義溯职;如果版本記錄表插入了一條記錄精盅,而附件表沒有插入記錄或者插入記錄少了幾條,也不符合一致性的定義谜酒。想要保持一致性叹俏,那么需要對這兩個表的插入操作都放在同一個事務(wù)內(nèi)進(jìn)行。

    在事務(wù)處理的ACID屬性中僻族,一致性是最基本的屬性粘驰,其它的三個屬性都為了保證一致性而存在的屡谐。

  • 原子性

    上面的轉(zhuǎn)賬的四個步驟要么全做,要么不做蝌数。假如做完第一步之后愕掏,計算機(jī)突然斷電了,那么數(shù)據(jù)庫重啟之后就需要執(zhí)行一個crash
    recovery的過程籽前,之前的所有操作都應(yīng)該回滾到執(zhí)行事務(wù)之前的狀態(tài)亭珍。即A向B轉(zhuǎn)賬的操作失敗了。

    上面提到枝哄,其他三個屬性都是為了保持一致性而存在肄梨。只要原子性是否就可以保證一致性?答案當(dāng)然是否定的挠锥。

    比如众羡,事務(wù)1 A向B轉(zhuǎn)賬100元,在第一步執(zhí)行完畢之后蓖租,恰好另外一個事務(wù)2操作是C向A轉(zhuǎn)賬200元粱侣,并且已經(jīng)執(zhí)行完畢,此時執(zhí)行事務(wù)1的第二步蓖宦,將A賬戶余額寫回數(shù)據(jù)庫齐婴,此時事務(wù)2的執(zhí)行結(jié)果就被事務(wù)1覆蓋掉了,造成了數(shù)據(jù)的不一致(A + B + C 的賬戶總額保持一致)稠茂。

    可見柠偶,即使事務(wù)1最終執(zhí)行完畢,滿足了原子性睬关,因為另一個事務(wù)的影響诱担,還是造成了數(shù)據(jù)的不一致狀態(tài)。原子性并不能保證一致性电爹。

    那么蔫仙,為什么會看到網(wǎng)上還有許多人再問原子性和一致性的問題呢?

    我認(rèn)為是程序員很容易從數(shù)據(jù)庫事務(wù)原子性聯(lián)想到做應(yīng)用時多線程并發(fā)時的原子性丐箩。多線程并發(fā)時的原子性基本靠鎖來維持摇邦,我們認(rèn)為,有了鎖的保護(hù)雏蛮,臨界區(qū)的資源就不可以被另一個線程訪問了涎嚼。事實上,數(shù)據(jù)庫事務(wù)原子性與鎖關(guān)系不大挑秉,鎖涉及到了事務(wù)的另一個特性:隔離性法梯。

  • 隔離性

    就像在上面談到的,事務(wù)1 與事務(wù)2 并行發(fā)生,造成了數(shù)據(jù)的不一致狀態(tài)立哑。隔離性用來解決這個問題夜惭。

    事務(wù)隔離性可以保證:如果在A給B轉(zhuǎn)賬的同時,有另外一個事務(wù)執(zhí)行了C給B轉(zhuǎn)賬的操作铛绰,那么當(dāng)兩個事務(wù)都結(jié)束的時候诈茧,B賬戶里面的錢應(yīng)該是A轉(zhuǎn)給B的錢加上C轉(zhuǎn)給B的錢再加上自己原有的錢。

  • 持久性

    持久性比較容易理解捂掰。即敢会,一旦事務(wù)提交(轉(zhuǎn)賬成功),所有的數(shù)據(jù)都會被寫入數(shù)據(jù)庫这嚣,落地到磁盤鸥昏。賬戶中的錢就真的發(fā)生了變化。

事務(wù)隔離性

從上文可以看出姐帚,當(dāng)并發(fā)事務(wù)同時訪問一個資源時吏垮,有可能導(dǎo)致數(shù)據(jù)不一致,因此需要一種機(jī)制來將數(shù)據(jù)訪問順序化罐旗,以保證數(shù)據(jù)庫數(shù)據(jù)的一致性膳汪。鎖就是其中的一種機(jī)制。我們通過使用鎖來保證事務(wù)隔離性九秀。

為了理解下面提到的隔離級別遗嗽,我們簡單認(rèn)識一下數(shù)據(jù)庫中的幾種鎖:

  • 從鎖粒度劃分

    表級鎖:開銷小,加鎖快鼓蜒;不會出現(xiàn)死鎖媳谁;鎖定粒度大,發(fā)生鎖沖突的概率最高友酱,并發(fā)度最低。

    行級鎖:開銷大柔纵,加鎖慢缔杉;會出現(xiàn)死鎖;鎖定粒度最小搁料,發(fā)生鎖沖突的概率最低或详,并發(fā)度也最高。

    頁面鎖:開銷和加鎖時間界于表鎖和行鎖之間郭计;會出現(xiàn)死鎖霸琴;鎖定粒度界于表鎖和行鎖之間,并發(fā)度一般昭伸。

  • 從鎖性質(zhì)劃分

    讀鎖(S 鎖):如果事務(wù)A對數(shù)據(jù)T加了該鎖之后梧乘,其他事務(wù)可以并發(fā)讀取T(獲取該數(shù)據(jù)的讀鎖),但任何事務(wù)都不能對數(shù)據(jù)T進(jìn)行修改(獲取數(shù)據(jù)上的寫鎖),直到已釋放所有讀鎖选调。

    寫鎖(X 鎖):如果事務(wù)A對數(shù)據(jù)T加上寫鎖后夹供,則其他事務(wù)不能再對T加任任何類型的鎖。獲得寫鎖的事務(wù)既能讀數(shù)據(jù)仁堪,又能修改數(shù)據(jù)哮洽。

    意向鎖: 設(shè)計目的主要是為了在一個事務(wù)中揭示下一行將要被請求鎖的類型。參考

    更新鎖:引入它是因為多數(shù)數(shù)據(jù)庫在實現(xiàn)加X鎖時是執(zhí)行了如下流程:先加S鎖弦聂,添加成功后嘗試更換為X鎖鸟辅。這時如果有兩個事務(wù)同時加了S鎖,嘗試換X鎖莺葫,就會發(fā)生死鎖匪凉。因此增加U鎖,U鎖代表有更新意向徙融,只允許有一個事務(wù)拿到U鎖洒缀,該事務(wù)在發(fā)生寫后U鎖變X鎖,未寫時看做S鎖欺冀。

隔離級別

我們知道了并發(fā)事務(wù)的隔離性靠鎖機(jī)制來實現(xiàn)树绩,很多DBMS定義了多個不同的"事務(wù)隔離等級"來控制鎖的程度和并發(fā)能力。

SQL定義的標(biāo)準(zhǔn)隔離級別有四種隐轩,從高到底依次為:

  • 可序列化(Serializable)

  • 可重復(fù)讀(Repeatable reads)

  • 提交讀(Read committed)

  • 未提交讀(Read uncommitted)

隨著數(shù)據(jù)庫隔離級別的提高饺饭,數(shù)據(jù)的并發(fā)能力也會有所下降。

下面了解一下這幾種隔離級別在數(shù)據(jù)庫中可能的實現(xiàn)职车。注意瘫俊,下面的實現(xiàn)都是基于傳統(tǒng)數(shù)據(jù)庫,而不是MVCC的悴灵。

未提交讀

  • 鎖機(jī)制:

    事務(wù)在讀數(shù)據(jù)的時候并未對數(shù)據(jù)加鎖扛芽;

    事務(wù)在修改數(shù)據(jù)的時候?qū)?shù)據(jù)增加行級S鎖。

  • 舉例:

Transaction 1 Transaction 2
select * from users where id = 1 // will read 20
update users set age = 21 where id = 1
select age from users where is = 1 // will read 21
roll back

事務(wù)一在讀取某行數(shù)據(jù)的時候并未加任何鎖积瞒,事務(wù)二也能對這行數(shù)據(jù)進(jìn)行讀取和更新川尖;

事務(wù)二在更新某行數(shù)據(jù)的時候?qū)@行數(shù)據(jù)加了S鎖,事務(wù)一可以對這行數(shù)據(jù)進(jìn)行讀取茫孔,因此看到了事務(wù)二未提交的更改;

事務(wù)二更新某行數(shù)據(jù)對這行數(shù)據(jù)加了S鎖缰贝,事務(wù)一不能對這行數(shù)據(jù)進(jìn)行更新馍悟,直到事務(wù)二結(jié)束。

可以看到剩晴,事務(wù)一第二次查詢看到了事務(wù)二未提交的更改,之后這些數(shù)據(jù)被事務(wù)二進(jìn)行了回滾毛嫉,于是事務(wù)一查詢到的數(shù)據(jù)就成了臟數(shù)據(jù)承粤,這種現(xiàn)象稱之為臟讀彻舰。

未提交讀會造成臟讀。

提交讀

  • 鎖機(jī)制

    事務(wù)對當(dāng)前被讀取的數(shù)據(jù)加行級S鎖(讀到時才加),一旦讀完該行就釋放S鎖唯卖;

    事務(wù)在更新某數(shù)據(jù)時昧廷,必須先對其加行級X鎖淹办,直到事務(wù)結(jié)束才釋放姥宝。

  • 舉例

Transaction 1 Transaction 2
select * from users where id =1 //will read 20
update users set age = 21 where id =1; commit
select * from users where id = 1 //will read 21

事務(wù)二在更新數(shù)據(jù)的時候?qū)?shù)據(jù)加了X鎖,直到事務(wù)結(jié)束才釋放。所以事務(wù)一讀取不到事務(wù)二未提交的數(shù)據(jù)穷缤。

事務(wù)二結(jié)束后事務(wù)一讀取到了與第一次讀取中不一致的數(shù)據(jù)。造成了事務(wù)一中兩次讀取的結(jié)果不一致,產(chǎn)生了不可重復(fù)讀問題笔呀。

可重復(fù)讀

  • 鎖機(jī)制

    事務(wù)對當(dāng)前被讀取的數(shù)據(jù)加行級S鎖许师,直到事務(wù)結(jié)束才釋放搭幻;

    事務(wù)在更新某數(shù)據(jù)時咧擂,對其加行級X鎖,直到事務(wù)結(jié)束才釋放檀蹋。

  • 舉例

Transaction 1 Transaction 2
select * from users where id =1; commit
update users set age = 21 where id =1; commit

事務(wù)一在讀取數(shù)據(jù)時松申,對數(shù)據(jù)加了S鎖,直到事務(wù)結(jié)束才釋放续扔。因此在此期間攻臀,事務(wù)二只能讀取該數(shù)據(jù),不能更新纱昧。這樣保證了事務(wù)一在整個事務(wù)期間刨啸,無論讀取多少次該數(shù)據(jù),結(jié)果都是一致的识脆,解決了不可重復(fù)讀的問題设联。

事務(wù)二在更新數(shù)據(jù)時對數(shù)據(jù)加了X鎖,直到事務(wù)結(jié)束才釋放灼捂,在此期間事務(wù)一都無法訪問和更新該數(shù)據(jù)离例,解決了臟讀的問題。

Transaction 1 Transaction 2
select * from users where age between 20 and 30
insert into users values(3, 'bob', 25); commit
select * from users where age between 20 and 30

上面的例子中:

事務(wù)一查詢年齡20到30之間的用戶悉稠,假設(shè)取到10條數(shù)據(jù)宫蛆,那么對這10條數(shù)據(jù)加上了行級S鎖;

事務(wù)二插入一條數(shù)據(jù)的猛。由于此時沒有任何事務(wù)對表添加了表級鎖耀盗,因此順利插入;

事務(wù)一再一次查詢年齡20到30之間的用戶卦尊,發(fā)現(xiàn)與第一次讀取時的數(shù)據(jù)不一致了叛拷,多出了一條數(shù)據(jù)。

這種現(xiàn)象就是幻讀岂却。這是一種特殊的不可重復(fù)讀現(xiàn)象忿薇。

可序列化

  • 鎖機(jī)制

    事務(wù)對當(dāng)前被讀取的數(shù)據(jù)加表級S鎖,直到事務(wù)結(jié)束才釋放躏哩;

    事務(wù)在更新某數(shù)據(jù)時署浩,對其加表級X鎖,直到事務(wù)結(jié)束才釋放扫尺。

事務(wù)一在讀取表記錄時筋栋,事務(wù)二也可以讀取該表,但不能對表進(jìn)行更新器联、刪除二汛、插入等操作;

事務(wù)一在更新表記錄時拨拓,事務(wù)二不能夠讀取該表的任何記錄肴颊,也不能對表進(jìn)行更新操作。

可序列化隔離級別避免了臟讀渣磷、不可重復(fù)讀和幻讀婿着,是最高的隔離級別。

參考

理解MySql事務(wù)隔離機(jī)制醋界、鎖以及各種鎖協(xié)議竟宋,mysql事務(wù)

事務(wù)并發(fā)的可能問題與其解決方案

Innodb中的事務(wù)隔離級別和鎖的關(guān)系

深入分析事務(wù)的隔離級別

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市形纺,隨后出現(xiàn)的幾起案子丘侠,更是在濱河造成了極大的恐慌,老刑警劉巖逐样,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜗字,死亡現(xiàn)場離奇詭異,居然都是意外死亡脂新,警方通過查閱死者的電腦和手機(jī)挪捕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來争便,“玉大人级零,你說我怎么就攤上這事≈鸵遥” “怎么了奏纪?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長酷宵。 經(jīng)常有香客問我亥贸,道長,這世上最難降的妖魔是什么浇垦? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任炕置,我火速辦了婚禮,結(jié)果婚禮上男韧,老公的妹妹穿的比我還像新娘朴摊。我一直安慰自己,他們只是感情好此虑,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布甚纲。 她就那樣靜靜地躺著,像睡著了一般朦前。 火紅的嫁衣襯著肌膚如雪介杆。 梳的紋絲不亂的頭發(fā)上鹃操,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機(jī)與錄音春哨,去河邊找鬼荆隘。 笑死,一個胖子當(dāng)著我的面吹牛赴背,可吹牛的內(nèi)容都是我干的椰拒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼凰荚,長吁一口氣:“原來是場噩夢啊……” “哼燃观!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起便瑟,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤缆毁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后胳徽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體积锅,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年养盗,在試婚紗的時候發(fā)現(xiàn)自己被綠了缚陷。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡往核,死狀恐怖箫爷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情聂儒,我是刑警寧澤虎锚,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站衩婚,受9級特大地震影響窜护,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜非春,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一柱徙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧奇昙,春花似錦护侮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至什湘,卻和暖如春长赞,著一層夾襖步出監(jiān)牢的瞬間晦攒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工得哆, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留勤家,地道東北人。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓柳恐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親热幔。 傳聞我的和親對象是個殘疾皇子乐设,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

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