MySQL事務(wù)

在關(guān)系型數(shù)據(jù)庫(kù)中搀捷,事務(wù)的重要性不言而喻奉芦,只要對(duì)數(shù)據(jù)庫(kù)稍有了解的人都知道事務(wù)具有 ACID 四個(gè)基本屬性,而我們不知道的可能就是數(shù)據(jù)庫(kù)是如何實(shí)現(xiàn)這四個(gè)屬性的骗奖;在這篇文章中确徙,我們將對(duì)事務(wù)的實(shí)現(xiàn)進(jìn)行分析,嘗試?yán)斫鈹?shù)據(jù)庫(kù)是如何實(shí)現(xiàn)事務(wù)的执桌,當(dāng)然我們也會(huì)在文章中簡(jiǎn)單對(duì) MySQL 中對(duì) ACID 的實(shí)現(xiàn)進(jìn)行簡(jiǎn)單的介紹鄙皇。

原子性(atomicity)

一致性(consistency)

隔離性(isolation)

持久性(durability)

事務(wù)其實(shí)就是并發(fā)控制的基本單位;相信我們都知道仰挣,事務(wù)是一個(gè)序列操作伴逸,其中的操作要么都執(zhí)行,要么都不執(zhí)行膘壶,它是一個(gè)不可分割的工作單位错蝴;接下來我們將依次介紹數(shù)據(jù)庫(kù)是如何實(shí)現(xiàn)這四個(gè)特性的。

事務(wù)的特性

原子性

在學(xué)習(xí)事務(wù)時(shí)颓芭,經(jīng)常有人會(huì)告訴你顷锰,事務(wù)就是一系列的操作,要么全部都執(zhí)行亡问,要都不執(zhí)行官紫,這其實(shí)就是對(duì)事務(wù)原子性的刻畫;雖然事務(wù)具有原子性玛界,但是原子性并不是只與事務(wù)有關(guān)系万矾,它的身影在很多地方都會(huì)出現(xiàn)。

由于操作并不具有原子性慎框,并且可以再分為多個(gè)操作,當(dāng)這些操作出現(xiàn)錯(cuò)誤或拋出異常時(shí)后添,整個(gè)操作就可能不會(huì)繼續(xù)執(zhí)行下去笨枯,而已經(jīng)進(jìn)行的操作造成的副作用就可能造成數(shù)據(jù)更新的丟失或者錯(cuò)誤。

事務(wù)其實(shí)和一個(gè)操作沒有什么太大的區(qū)別,它是一系列的數(shù)據(jù)庫(kù)操作(可以理解為 SQL)的集合馅精,如果事務(wù)不具備原子性严嗜,那么就沒辦法保證同一個(gè)事務(wù)中的所有操作都被執(zhí)行或者未被執(zhí)行了,整個(gè)數(shù)據(jù)庫(kù)系統(tǒng)就既不可用也不可信洲敢。

隔離性

事務(wù)的隔離性要求每個(gè)讀寫事務(wù)的對(duì)象對(duì)其他事務(wù)的操作對(duì)象能互相分離漫玄,即該事務(wù)提交前對(duì)其他事物都不可見,通常這使用鎖來實(shí)現(xiàn)压彭。當(dāng)前數(shù)據(jù)庫(kù)系統(tǒng)中都提供一種粒度鎖的策略睦优,允許事務(wù)僅鎖住一個(gè)實(shí)體對(duì)象的子集,以此來提高事物之間的并發(fā)度壮不。

持久性

既然是數(shù)據(jù)庫(kù)汗盘,那么一定對(duì)數(shù)據(jù)的持久存儲(chǔ)有著非常強(qiáng)烈的需求,如果數(shù)據(jù)被寫入到數(shù)據(jù)庫(kù)中询一,那么數(shù)據(jù)一定能夠被安全存儲(chǔ)在磁盤上隐孽;而事務(wù)的持久性就體現(xiàn)在,一旦事務(wù)被提交健蕊,那么數(shù)據(jù)一定會(huì)被寫入到數(shù)據(jù)庫(kù)中并持久存儲(chǔ)起來菱阵。

當(dāng)事務(wù)已經(jīng)被提交之后,就無法再次回滾了缩功,唯一能夠撤回已經(jīng)提交的事務(wù)的方式就是創(chuàng)建一個(gè)相反的事務(wù)對(duì)原操作進(jìn)行『補(bǔ)償』晴及,這也是事務(wù)持久性的體現(xiàn)之一。

一致性

一致性是指事務(wù)將數(shù)據(jù)庫(kù)從一種狀態(tài)變?yōu)橄乱环N狀態(tài)掂之。在事務(wù)開始之前和事務(wù)結(jié)束之后抗俄,數(shù)據(jù)庫(kù)的完整性約束沒有被破壞。即在事務(wù)的執(zhí)行的前后以及過程中不會(huì)違背對(duì)數(shù)據(jù)完整性的約束世舰,所有對(duì)數(shù)據(jù)庫(kù)寫入的操作都應(yīng)該是合法的动雹,并不能產(chǎn)生不合法的數(shù)據(jù)狀態(tài)。

事務(wù)的實(shí)現(xiàn)

事務(wù)的隔離性由鎖來實(shí)現(xiàn)跟压,原子性胰蝠、一致性、持久性通過數(shù)據(jù)庫(kù)的redo log和undo log來完成震蒋。redo log稱為重做日志茸塞,用來保證事物的原子性和持久性。undo log稱為回滾日志查剖,用來保證事務(wù)的一致性钾虐,幫助事務(wù)回滾及MVCC的功能。

redo恢復(fù)提交事務(wù)修改的頁操作笋庄,而undo回滾行記錄到某個(gè)特定版本效扫。因此兩者記錄的內(nèi)容不同倔监,redo通常是物理日志,記錄的是頁的物理修改操作菌仁。undo是邏輯日志浩习,根據(jù)每行記錄進(jìn)行記錄。

重做日志(redo log)

重做日志由兩部分組成:一是內(nèi)存中的重做日志緩沖济丘,其是易失的谱秽;二是重做日志文件,其是持久的摹迷。

當(dāng)事務(wù)提交時(shí)疟赊,必須先將該事物的所有日志寫入到重做日志文件進(jìn)行持久化,呆事物的COMMIT操作完成才算完成泪掀。

這里的事務(wù)日志指的就是redo log和undo log听绳。

redo log

當(dāng)我們?cè)谝粋€(gè)事務(wù)中嘗試對(duì)數(shù)據(jù)進(jìn)行修改時(shí),它會(huì)先將數(shù)據(jù)從磁盤讀入內(nèi)存异赫,并更新內(nèi)存中緩存的數(shù)據(jù)椅挣,然后生成一條重做日志并寫入重做日志緩存,當(dāng)事務(wù)真正提交時(shí)塔拳,MySQL 會(huì)將重做日志緩存中的內(nèi)容刷新到重做日志文件鼠证,再將內(nèi)存中的數(shù)據(jù)更新到磁盤上,圖中的第 4靠抑、5 步就是在事務(wù)提交時(shí)執(zhí)行的量九。

在 InnoDB 中,重做日志都是以 512 字節(jié)的塊的形式進(jìn)行存儲(chǔ)的颂碧,同時(shí)因?yàn)閴K的大小與磁盤扇區(qū)大小相同荠列,所以重做日志的寫入可以保證原子性,不會(huì)由于機(jī)器斷電導(dǎo)致重做日志僅寫入一半并留下臟數(shù)據(jù)载城。

除了所有對(duì)數(shù)據(jù)庫(kù)的修改會(huì)產(chǎn)生重做日志肌似,因?yàn)榛貪L日志也是需要持久存儲(chǔ)的,它們也會(huì)創(chuàng)建對(duì)應(yīng)的重做日志诉瓦,在發(fā)生錯(cuò)誤后川队,數(shù)據(jù)庫(kù)重啟時(shí)會(huì)從重做日志中找出未被更新到數(shù)據(jù)庫(kù)磁盤中的日志重新執(zhí)行以滿足事務(wù)的持久性。

在MySQL數(shù)據(jù)庫(kù)中還有一種二進(jìn)制日志睬澡,其用來進(jìn)行POINT-IN-TIME的恢復(fù)及主從復(fù)制環(huán)境的建立固额。從表面上看其和重做日志非常相似,都是記錄了對(duì)于數(shù)據(jù)庫(kù)操作的日志煞聪。然而本質(zhì)上來看斗躏,兩者有著非常大的不同。

首先昔脯,重做日志是在InnoDB存儲(chǔ)引擎層產(chǎn)生瑟捣,而二進(jìn)制日志是在MySQL數(shù)據(jù)庫(kù)的上層產(chǎn)生馋艺,并且二進(jìn)制日志不僅僅針對(duì)于InnoDB存儲(chǔ)引擎栅干,MySQL數(shù)據(jù)庫(kù)中的任意存儲(chǔ)引擎對(duì)于數(shù)據(jù)庫(kù)的更改都會(huì)產(chǎn)生二進(jìn)制日志迈套。

其次,兩種日志記錄的內(nèi)容形式不同碱鳞,二進(jìn)制日志是一種邏輯日志桑李,記錄對(duì)應(yīng)的SQL語句。重做日志是物理格式日志窿给,記錄的是對(duì)于每個(gè)頁的修改贵白。

此外,二進(jìn)制日志只在事務(wù)提交完成后進(jìn)行一次寫入崩泡。而重做日志在事務(wù)進(jìn)行中不斷地被寫入禁荒。

回滾日志(undo log)

想要保證事務(wù)的原子性,就需要在異常發(fā)生時(shí)角撞,對(duì)已經(jīng)執(zhí)行的操作進(jìn)行回滾呛伴,而在 MySQL 中,恢復(fù)機(jī)制是通過回滾日志(undo log)實(shí)現(xiàn)的谒所,所有事務(wù)進(jìn)行的修改都會(huì)先記錄到這個(gè)回滾日志中热康,然后在對(duì)數(shù)據(jù)庫(kù)中的對(duì)應(yīng)行進(jìn)行寫入。

undo log

這個(gè)過程其實(shí)非常好理解劣领,為了能夠在發(fā)生錯(cuò)誤時(shí)撤銷之前的全部操作姐军,肯定是需要將之前的操作都記錄下來的,這樣在發(fā)生錯(cuò)誤時(shí)才可以回滾尖淘。

回滾日志除了能夠在發(fā)生錯(cuò)誤或者用戶執(zhí)行ROLLBACK時(shí)提供回滾相關(guān)的信息奕锌,它還能夠在整個(gè)系統(tǒng)發(fā)生崩潰、數(shù)據(jù)庫(kù)進(jìn)程直接被殺死后村生,當(dāng)用戶再次啟動(dòng)數(shù)據(jù)庫(kù)進(jìn)程時(shí)惊暴,還能夠立刻通過查詢回滾日志將之前未完成的事務(wù)進(jìn)行回滾,這也就需要回滾日志必須先于數(shù)據(jù)持久化到磁盤上梆造,是我們需要先寫日志后寫數(shù)據(jù)庫(kù)的主要原因缴守。

回滾日志并不能將數(shù)據(jù)庫(kù)物理地恢復(fù)到執(zhí)行語句或者事務(wù)之前的樣子;它是邏輯日志镇辉,當(dāng)回滾日志被使用時(shí)屡穗,它只會(huì)按照日志邏輯地將數(shù)據(jù)庫(kù)中的修改撤銷掉看,可以理解為忽肛,我們?cè)谑聞?wù)中使用的每一條INSERT都對(duì)應(yīng)了一條DELETE村砂,每一條UPDATE也都對(duì)應(yīng)一條相反的UPDATE語句。

這是因?yàn)樵诖罅渴聞?wù)并發(fā)時(shí)屹逛,一個(gè)事務(wù)在修改當(dāng)前一個(gè)頁中某幾條記錄础废,同時(shí)還有別的事務(wù)在對(duì)同一個(gè)頁中另幾條記錄進(jìn)行修改汛骂。此時(shí)不能將頁回滾到事務(wù)開始的樣子,因?yàn)檫@樣會(huì)影響其他的事務(wù)正在進(jìn)行的工作评腺。

邏輯回滾

重做日志與回滾日志

發(fā)生錯(cuò)誤或者需要回滾的事務(wù)能夠利用回滾日志進(jìn)行回滾(原子性)帘瞭;

在事務(wù)提交后,數(shù)據(jù)沒來得及寫會(huì)磁盤就宕機(jī)時(shí)蒿讥,在下次重新啟動(dòng)后能夠利用重做日志恢復(fù)數(shù)據(jù)(持久性)蝶念;

重做日志存放在重做日志文件中,而回滾日志存放在數(shù)據(jù)庫(kù)內(nèi)部的一個(gè)特殊段(segment)中芋绸,這個(gè)段稱為undo段媒殉。undo段位于共享表空間中。

在數(shù)據(jù)庫(kù)中摔敛,這兩種日志經(jīng)常都是一起工作的廷蓉,我們可以將它們整體看做一條事務(wù)日志,其中包含了事務(wù)的 ID马昙、修改的行元素以及修改前后的值桃犬。

事務(wù)日志

對(duì)事務(wù)操作的統(tǒng)計(jì)

由于InnoDB存儲(chǔ)引擎是支持事務(wù)的,因此InnoDB存儲(chǔ)引擎的應(yīng)用需要在考慮每秒請(qǐng)求數(shù)(QPS)的同時(shí)给猾,關(guān)注每秒事務(wù)處理(TPS)的能力疫萤。

計(jì)算TPS的方法是(com_commit+com_rollback)/time。

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

數(shù)據(jù)庫(kù)的隔離性和一致性其實(shí)是一個(gè)需要開發(fā)者去權(quán)衡的問題敢伸,為數(shù)據(jù)庫(kù)提供什么樣的隔離性層級(jí)也就決定了數(shù)據(jù)庫(kù)的性能以及可以達(dá)到什么樣的一致性扯饶;

在 SQL 標(biāo)準(zhǔn)中定義了四種數(shù)據(jù)庫(kù)的事務(wù)的隔離級(jí)別:READ UNCOMMITED、READ COMMITED池颈、REPEATABLE READ?和?SERIALIZABLE尾序;每個(gè)事務(wù)的隔離級(jí)別其實(shí)都比上一級(jí)多解決了一個(gè)問題:

RAED UNCOMMITED:可能會(huì)讀到未提交的行(Dirty Read),即可能發(fā)生臟讀躯砰;

READ COMMITED:沒有臟讀每币,但多次讀取某一行的值可能會(huì)發(fā)生變化,即可能發(fā)生不可重復(fù)讀琢歇;

REPEATABLE READ:可重復(fù)讀兰怠,每次讀取同一行的值都是不變的,但可能讀取到之前沒有的行李茫,即可能發(fā)生幻讀揭保;

SERIALIZABLE:解決了幻讀的問題;

由于鎖的存在魄宏,以上的所有的事務(wù)隔離級(jí)別都不允許臟寫入(Dirty Write)秸侣,也就是當(dāng)前事務(wù)更新了另一個(gè)事務(wù)已經(jīng)更新但是還未提交的數(shù)據(jù)。

大部分的數(shù)據(jù)庫(kù)中都使用了 READ COMMITED 作為默認(rèn)的事務(wù)隔離級(jí)別,但是 InnoDB 使用了 REPEATABLE READ 作為默認(rèn)配置味榛,但與標(biāo)準(zhǔn)SQL不同的是椭坚,InnoDB存儲(chǔ)引擎在REPEATABLE READ事務(wù)隔離級(jí)別下,使用Next-key Lock鎖的算法搏色,因此避免幻讀的產(chǎn)生善茎。

一般情況來說,從 RAED UNCOMMITED 到 SERIALIZABLE继榆,隨著事務(wù)隔離級(jí)別變得越來越嚴(yán)格巾表,數(shù)據(jù)庫(kù)對(duì)于并發(fā)執(zhí)行事務(wù)的性能也逐漸下降。

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

參考

MySQL技術(shù)內(nèi)幕

『淺入深出』MySQL 中事務(wù)的實(shí)現(xiàn)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末略吨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子考阱,更是在濱河造成了極大的恐慌翠忠,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乞榨,死亡現(xiàn)場(chǎng)離奇詭異秽之,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)吃既,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門考榨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鹦倚,你說我怎么就攤上這事河质。” “怎么了震叙?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵掀鹅,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我媒楼,道長(zhǎng)乐尊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任划址,我火速辦了婚禮扔嵌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘夺颤。我一直安慰自己痢缎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布拂共。 她就那樣靜靜地躺著牺弄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪宜狐。 梳的紋絲不亂的頭發(fā)上势告,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天蛇捌,我揣著相機(jī)與錄音,去河邊找鬼咱台。 笑死络拌,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的回溺。 我是一名探鬼主播春贸,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼遗遵!你這毒婦竟也來了萍恕?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤车要,失蹤者是張志新(化名)和其女友劉穎允粤,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體翼岁,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡类垫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了琅坡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片悉患。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖榆俺,靈堂內(nèi)的尸體忽然破棺而出售躁,到底是詐尸還是另有隱情,我是刑警寧澤谴仙,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布迂求,位于F島的核電站,受9級(jí)特大地震影響晃跺,放射性物質(zhì)發(fā)生泄漏揩局。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一掀虎、第九天 我趴在偏房一處隱蔽的房頂上張望凌盯。 院中可真熱鬧,春花似錦烹玉、人聲如沸驰怎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽县忌。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間症杏,已是汗流浹背装获。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留厉颤,地道東北人穴豫。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像逼友,于是被迫代替她去往敵國(guó)和親精肃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

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