MySQL事務(wù)特性及隔離級(jí)別

什么是事務(wù)?

事務(wù)是邏輯上的一組操作袒哥,要么都執(zhí)行走诞,要么都不執(zhí)行会油。

事務(wù)最經(jīng)典也經(jīng)常被拿出來(lái)說例子就是轉(zhuǎn)賬了妥曲。

假如小明要給小紅轉(zhuǎn)賬1000元,這個(gè)轉(zhuǎn)賬會(huì)涉及到兩個(gè)關(guān)鍵操作就是:將小明的余額減少1000元钦购,將小紅的余額增加1000元檐盟。萬(wàn)一在這兩個(gè)操作之間突然出現(xiàn)錯(cuò)誤比如銀行系統(tǒng)崩潰,導(dǎo)致小明余額減少而小紅的余額沒有增加押桃,這樣就不對(duì)了葵萎。事務(wù)就是保證這兩個(gè)關(guān)鍵操作要么都成功,要么都要失敗唱凯。

事物的特性(ACID)

image
  • 原子性(Atomicity): 事務(wù)是最小的執(zhí)行單位陌宿,不允許分割。事務(wù)的原子性確保動(dòng)作要么全部完成波丰,要么完全不起作用壳坪;因此事務(wù)的操作如果成功就必須要完全應(yīng)用到數(shù)據(jù)庫(kù),如果操作失敗則不能對(duì)數(shù)據(jù)庫(kù)有任何影響掰烟。
  • 一致性(Consistency): 執(zhí)行事務(wù)前后爽蝴,數(shù)據(jù)保持一致;一致性是指事務(wù)必須使數(shù)據(jù)庫(kù)從一個(gè)一致性狀態(tài)變換到另一個(gè)一致性狀態(tài)纫骑,也就是說一個(gè)事務(wù)執(zhí)行之前和執(zhí)行之后都必須處于一致性狀態(tài)蝎亚。拿轉(zhuǎn)賬來(lái)說,小明和小紅兩者的錢加起來(lái)一共是5000先馆,那么不管A和B之間如何轉(zhuǎn)賬发框,轉(zhuǎn)幾次賬,事務(wù)結(jié)束后兩個(gè)用戶的錢相加起來(lái)應(yīng)該還得是5000煤墙,這就是事務(wù)的一致性梅惯。
  • 隔離性(Isolation): 并發(fā)訪問數(shù)據(jù)庫(kù)時(shí),一個(gè)用戶的事物不被其他事物所干擾仿野,各并發(fā)事務(wù)之間數(shù)據(jù)庫(kù)是獨(dú)立的铣减;當(dāng)多個(gè)用戶并發(fā)訪問數(shù)據(jù)庫(kù)時(shí),比如操作同一張表時(shí)脚作,數(shù)據(jù)庫(kù)為每一個(gè)用戶開啟的事務(wù)葫哗,不能被其他事務(wù)的操作所干擾,多個(gè)并發(fā)事務(wù)之間要相互隔離球涛。即要達(dá)到這么一種效果:對(duì)于任意兩個(gè)并發(fā)的事務(wù)T1和T2劣针,在事務(wù)T1看來(lái),T2要么在T1開始之前就已經(jīng)結(jié)束亿扁,要么在T1結(jié)束之后才開始捺典,這樣每個(gè)事務(wù)都感覺不到有其他事務(wù)在并發(fā)地執(zhí)行。
  • 持久性(Durability): 一個(gè)事務(wù)被提交之后魏烫。它對(duì)數(shù)據(jù)庫(kù)中數(shù)據(jù)的改變是持久的辣苏,即使數(shù)據(jù)庫(kù)發(fā)生故障也不應(yīng)該對(duì)其有任何影響肝箱。例如我們?cè)谑褂肑DBC操作數(shù)據(jù)庫(kù)時(shí),在提交事務(wù)方法后稀蟋,提示用戶事務(wù)操作完成煌张,當(dāng)我們程序執(zhí)行完成直到看到提示后,就可以認(rèn)定事務(wù)以及正確提交退客,即使這時(shí)候數(shù)據(jù)庫(kù)出現(xiàn)了問題骏融,也必須要將我們的事務(wù)完全執(zhí)行完成,否則就會(huì)造成我們看到提示事務(wù)處理完畢萌狂,但是數(shù)據(jù)庫(kù)因?yàn)楣收隙鴽]有執(zhí)行事務(wù)的重大錯(cuò)誤档玻。

并發(fā)事務(wù)帶來(lái)的問題

在典型的應(yīng)用程序中,多個(gè)事務(wù)并發(fā)運(yùn)行茫藏,經(jīng)常會(huì)操作相同的數(shù)據(jù)來(lái)完成各自的任務(wù)(多個(gè)用戶對(duì)統(tǒng)一數(shù)據(jù)進(jìn)行操作)误趴。并發(fā)雖然是必須的,但可能會(huì)導(dǎo)致以下的問題务傲。

  • 臟讀(Dirty read): 當(dāng)一個(gè)事務(wù)正在訪問數(shù)據(jù)并且對(duì)數(shù)據(jù)進(jìn)行了修改凉当,而這種修改還沒有提交到數(shù)據(jù)庫(kù)中,這時(shí)另外一個(gè)事務(wù)也訪問了這個(gè)數(shù)據(jù)售葡,然后使用了這個(gè)數(shù)據(jù)看杭。因?yàn)檫@個(gè)數(shù)據(jù)是還沒有提交的數(shù)據(jù),那么另外一個(gè)事務(wù)讀到的這個(gè)數(shù)據(jù)是“臟數(shù)據(jù)”挟伙,依據(jù)“臟數(shù)據(jù)”所做的操作可能是不正確的楼雹。

    例如:小紅向小明轉(zhuǎn)賬100元,對(duì)應(yīng)SQL命令如下

        update account set money=money+100 where name=’小明’;  (此時(shí)小紅通知小明)
    
        update account set money=money - 100 where name=’小紅’;
    
    

    當(dāng)只執(zhí)行第一條SQL時(shí)尖阔,小紅通知小明查看賬戶贮缅,發(fā)現(xiàn)確實(shí)錢已到賬(此時(shí)即發(fā)生了臟讀),而之后無(wú)論第二條SQL是否執(zhí)行诺祸,只要該事務(wù)不提交携悯,則所有操作都將回滾,那么當(dāng)B以后再次查看賬戶時(shí)就會(huì)發(fā)現(xiàn)錢其實(shí)并沒有轉(zhuǎn)筷笨。

  • 丟失修改(Lost to modify): 指在一個(gè)事務(wù)讀取一個(gè)數(shù)據(jù)時(shí),另外一個(gè)事務(wù)也訪問了該數(shù)據(jù)龟劲,那么在第一個(gè)事務(wù)中修改了這個(gè)數(shù)據(jù)后胃夏,第二個(gè)事務(wù)也修改了這個(gè)數(shù)據(jù)。這樣第一個(gè)事務(wù)內(nèi)的修改結(jié)果就被丟失昌跌,因此稱為丟失修改仰禀。

    例如:事務(wù)1讀取某表中的數(shù)據(jù)A=20,事務(wù)2也讀取A=20蚕愤,事務(wù)1修改A=A-1答恶,事務(wù)2也修改A=A-1饺蚊,最終結(jié)果A=19,事務(wù)1的修改被丟失悬嗓。

  • 不可重復(fù)讀(Unrepeatableread): 指在一個(gè)事務(wù)內(nèi)多次讀同一數(shù)據(jù)污呼。在這個(gè)事務(wù)還沒有結(jié)束時(shí),另一個(gè)事務(wù)也訪問該數(shù)據(jù)包竹。那么燕酷,在第一個(gè)事務(wù)中的兩次讀數(shù)據(jù)之間,由于第二個(gè)事務(wù)的修改導(dǎo)致第一個(gè)事務(wù)兩次讀取的數(shù)據(jù)可能不太一樣周瞎。這就發(fā)生了在一個(gè)事務(wù)內(nèi)兩次讀到的數(shù)據(jù)是不一樣的情況苗缩,因此稱為不可重復(fù)讀。

    例如事務(wù)T1在讀取某一數(shù)據(jù)声诸,而事務(wù)T2立馬修改了這個(gè)數(shù)據(jù)并且提交事務(wù)給數(shù)據(jù)庫(kù)酱讶,事務(wù)T1再次讀取該數(shù)據(jù)就得到了不同的結(jié)果,發(fā)送了不可重復(fù)讀彼乌。

  • 幻讀(Phantom read): 幻讀與不可重復(fù)讀類似泻肯。它發(fā)生在一個(gè)事務(wù)(T1)讀取了幾行數(shù)據(jù),接著另一個(gè)并發(fā)事務(wù)(T2)插入了一些數(shù)據(jù)時(shí)囤攀。在隨后的查詢中软免,第一個(gè)事務(wù)(T1)就會(huì)發(fā)現(xiàn)多了一些原本不存在的記錄,就好像發(fā)生了幻覺一樣焚挠,所以稱為幻讀膏萧。


不可重復(fù)讀和臟讀的區(qū)別:

臟讀是某一事務(wù)讀取了另一個(gè)事務(wù)未提交的臟數(shù)據(jù),而不可重復(fù)讀則是讀取了前一事務(wù)提交的數(shù)據(jù)蝌衔。

在某些情況下榛泛,不可重復(fù)讀并不是問題,比如我們多次查詢某個(gè)數(shù)據(jù)當(dāng)然以最后查詢得到的結(jié)果為主噩斟。但在另一些情況下就有可能發(fā)生問題曹锨,例如對(duì)于同一個(gè)數(shù)據(jù)A和B依次查詢就可能不同,A和B就可能打起來(lái)了……

不可重復(fù)度和幻讀區(qū)別:

不可重復(fù)讀的重點(diǎn)是修改剃允,幻讀的重點(diǎn)在于新增或者刪除沛简。

例1(同樣的條件, 你讀取過的數(shù)據(jù), 再次讀取出來(lái)發(fā)現(xiàn)值不一樣了 ):事務(wù)1中的A先生讀取自己的工資為 1000的操作還沒完成,事務(wù)2中的B先生就修改了A的工資為2000斥废,導(dǎo) 致A再讀自己的工資時(shí)工資變?yōu)?2000椒楣;這就是不可重復(fù)讀。

例2(同樣的條件, 第1次和第2次讀出來(lái)的記錄數(shù)不一樣 ):假某工資單表中工資大于3000的有4人牡肉,事務(wù)1讀取了所有工資大于3000的人捧灰,共查到4條記錄,這時(shí)事務(wù)2 又插入了一條工資大于3000的記錄统锤,事務(wù)1再次讀取時(shí)查到的記錄就變?yōu)榱?條毛俏,這樣就導(dǎo)致了幻讀炭庙。

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

現(xiàn)在來(lái)看看MySQL數(shù)據(jù)庫(kù)為我們提供的四種隔離級(jí)別:

① Serializable (串行化)

最高的隔離級(jí)別,完全服從ACID的隔離級(jí)別煌寇。所有的事務(wù)依次逐個(gè)執(zhí)行焕蹄,這樣事務(wù)之間就完全不可能產(chǎn)生干擾,也就是說唧席,該級(jí)別可避免臟讀擦盾、不可重復(fù)讀、幻讀的發(fā)生淌哟。迹卢。

② Repeatable read (可重復(fù)讀)

對(duì)同一字段的多次讀取結(jié)果都是一致的,除非數(shù)據(jù)是被本身事務(wù)自己所修改徒仓,可以阻止臟讀和不可重復(fù)讀腐碱,但幻讀仍有可能發(fā)生

③ Read committed (讀已提交)

允許讀取并發(fā)事務(wù)已經(jīng)提交的數(shù)據(jù)掉弛,可以阻止臟讀症见,但是幻讀或不可重復(fù)讀仍有可能發(fā)生

④ Read uncommitted (讀未提交)

最低的隔離級(jí)別,允許讀取尚未提交的數(shù)據(jù)變更殃饿,可能會(huì)導(dǎo)致臟讀谋作、幻讀或不可重復(fù)讀

以上四種隔離級(jí)別最高的是Serializable級(jí)別,最低的是Read uncommitted級(jí)別乎芳,當(dāng)然級(jí)別越高遵蚜,執(zhí)行效率就越低。像Serializable這樣的級(jí)別奈惑,就是以鎖表的方式(類似于Java多線程中的鎖)使得其他的線程只能在鎖外等待吭净,所以平時(shí)選用何種隔離級(jí)別應(yīng)該根據(jù)實(shí)際情況。在MySQL數(shù)據(jù)庫(kù)中默認(rèn)的隔離級(jí)別為Repeatable read (可重復(fù)讀)肴甸。

在MySQL數(shù)據(jù)庫(kù)中寂殉,支持上面四種隔離級(jí)別, InnoDB 存儲(chǔ)引擎的默認(rèn)支持的隔離級(jí)別是Repeatable read (可重復(fù)讀)原在;而在Oracle數(shù)據(jù)庫(kù)中友扰,只支持Serializable (串行化)級(jí)別和Read committed (讀已提交)這兩種級(jí)別,其中默認(rèn)的為Read committed級(jí)別庶柿。

在MySQL數(shù)據(jù)庫(kù)中查看當(dāng)前事務(wù)的隔離級(jí)別:

    select @@tx_isolation;

在MySQL數(shù)據(jù)庫(kù)中設(shè)置事務(wù)的隔離 級(jí)別:

    set  [glogal | session]  transaction isolation level 隔離級(jí)別名稱;

    set tx_isolation=’隔離級(jí)別名稱;’

例1:查看當(dāng)前事務(wù)的隔離級(jí)別:

image

例2:將事務(wù)的隔離級(jí)別設(shè)置為Read uncommitted級(jí)別:

image

或:

image

記谆烂省:設(shè)置數(shù)據(jù)庫(kù)的隔離級(jí)別一定要是在開啟事務(wù)之前!

這里需要注意的是:與 SQL 標(biāo)準(zhǔn)不同的地方在于InnoDB 存儲(chǔ)引擎在 REPEATABLE-READ(可重讀)事務(wù)隔離級(jí)別下使用的是Next-Key Lock 鎖算法澳泵,因此可以避免幻讀的產(chǎn)生,這與其他數(shù)據(jù)庫(kù)系統(tǒng)(如 SQL Server)是不同的兼呵。所以說InnoDB 存儲(chǔ)引擎的默認(rèn)支持的隔離級(jí)別是 REPEATABLE-READ(可重讀) 已經(jīng)可以完全保證事務(wù)的隔離性要求兔辅,即達(dá)到了 SQL標(biāo)準(zhǔn)的SERIALIZABLE(可串行化)隔離級(jí)別腊敲。

因?yàn)楦綦x級(jí)別越低,事務(wù)請(qǐng)求的鎖越少维苔,所以大部分?jǐn)?shù)據(jù)庫(kù)系統(tǒng)的隔離級(jí)別都是READ-COMMITTED(讀取提交內(nèi)容):碰辅,但是你要知道的是InnoDB 存儲(chǔ)引擎默認(rèn)使用 REPEATABLE-READ(可重讀)并不會(huì)有任何性能損失。

InnoDB 存儲(chǔ)引擎在 分布式事務(wù) 的情況下一般會(huì)用到SERIALIZABLE(可串行化)隔離級(jí)別介时。

實(shí)際情況演示

MySQL 命令行的默認(rèn)配置中事務(wù)都是自動(dòng)提交的没宾,即執(zhí)行SQL語(yǔ)句后就會(huì)馬上執(zhí)行 COMMIT 操作。如果要顯式地開啟一個(gè)事務(wù)需要使用命令:START TARNSACTION沸柔。

我們可以通過下面的命令來(lái)設(shè)置隔離級(jí)別循衰。

SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE]

我們?cè)賮?lái)看一下我們?cè)谙旅鎸?shí)際操作中使用到的一些并發(fā)控制語(yǔ)句:

?START TARNSACTION |BEGIN:顯式地開啟一個(gè)事務(wù)。

?COMMIT:提交事務(wù)褐澎,使得對(duì)數(shù)據(jù)庫(kù)做的所有修改成為永久性会钝。

?ROLLBACK 回滾會(huì)結(jié)束用戶的事務(wù),并撤銷正在進(jìn)行的所有未提交的修改工三。

在下面我會(huì)使用 2 個(gè)命令行 MySQL 迁酸,模擬多線程(多事務(wù))。

臟讀(讀未提交)

image

避免臟讀(讀已提交)

image

不可重復(fù)讀

還是剛才上面的讀已提交的圖俭正,雖然避免了讀未提交奸鬓,但是卻出現(xiàn)了,一個(gè)事務(wù)還沒有結(jié)束掸读,就發(fā)生了 不可重復(fù)讀問題串远。

image

可重復(fù)讀

image

防止幻讀(可重復(fù)讀)

image

一個(gè)事務(wù)對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作,這種操作的范圍是數(shù)據(jù)庫(kù)的全部行寺枉,然后第二個(gè)事務(wù)也在對(duì)這個(gè)數(shù)據(jù)庫(kù)操作抑淫,這種操作可以是插入一行記錄或刪除一行記錄,那么第一個(gè)是事務(wù)就會(huì)覺得自己出現(xiàn)了幻覺姥闪,怎么還有沒有處理的記錄呢? 或者 怎么多處理了一行記錄呢?

幻讀和不可重復(fù)讀有些相似之處 始苇,但是不可重復(fù)讀的重點(diǎn)是修改,幻讀的重點(diǎn)在于新增或者刪除筐喳。

參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末催式,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子避归,更是在濱河造成了極大的恐慌荣月,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梳毙,死亡現(xiàn)場(chǎng)離奇詭異哺窄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門萌业,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)坷襟,“玉大人,你說我怎么就攤上這事生年∮こ蹋” “怎么了?”我有些...
    開封第一講書人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵抱婉,是天一觀的道長(zhǎng)档叔。 經(jīng)常有香客問我,道長(zhǎng)蒸绩,這世上最難降的妖魔是什么衙四? 我笑而不...
    開封第一講書人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮侵贵,結(jié)果婚禮上届搁,老公的妹妹穿的比我還像新娘。我一直安慰自己窍育,他們只是感情好卡睦,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著漱抓,像睡著了一般表锻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上乞娄,一...
    開封第一講書人閱讀 49,792評(píng)論 1 290
  • 那天瞬逊,我揣著相機(jī)與錄音,去河邊找鬼仪或。 笑死确镊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的范删。 我是一名探鬼主播蕾域,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼到旦!你這毒婦竟也來(lái)了旨巷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤添忘,失蹤者是張志新(化名)和其女友劉穎采呐,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體搁骑,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡斧吐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年又固,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片会通。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡口予,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出涕侈,到底是詐尸還是另有隱情,我是刑警寧澤煤辨,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布裳涛,位于F島的核電站,受9級(jí)特大地震影響众辨,放射性物質(zhì)發(fā)生泄漏端三。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一鹃彻、第九天 我趴在偏房一處隱蔽的房頂上張望郊闯。 院中可真熱鬧,春花似錦蛛株、人聲如沸团赁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)欢摄。三九已至,卻和暖如春笋粟,著一層夾襖步出監(jiān)牢的瞬間怀挠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工害捕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绿淋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓尝盼,卻偏偏與公主長(zhǎng)得像吞滞,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子东涡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348

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

  • 空氣中飄蕩著他的朗讀聲冯吓,不由自主地想到以后,這樣的生活真的很不錯(cuò)疮跑,老肖组贺,我忍不住想用一支錄音筆把你念給我的東西全部...
    午夜的月光閱讀 127評(píng)論 0 0
  • 圖書館東門安置的迎新生展臺(tái)前人群攢動(dòng),喧囂的熱鬧打破了圖書館里沉悶寧?kù)o的學(xué)習(xí)氣氛掀潮,混雜在一起的廣播和音樂提醒著我這...
    烏蒙山天連天閱讀 325評(píng)論 0 0