MySQL InnnoDB 存儲(chǔ)引擎事務(wù)

事務(wù)(Transaction)是數(shù)據(jù)庫區(qū)別于文件系統(tǒng)的重要特性之一界拦。事務(wù)會(huì)把數(shù)據(jù)庫從一種一致狀態(tài)轉(zhuǎn)換為另一種一致狀態(tài)。
事務(wù)可由一條非常簡單的 SQL 語句組成爪幻,也可以由一組復(fù)雜的 SQL 語句組成宗弯。事務(wù)是訪問并更新數(shù)據(jù)庫中各種數(shù)據(jù)項(xiàng)的一個(gè)程序執(zhí)行單元愤估。在事務(wù)中的操作,要么都做修改打洼,要么都不做龄糊。

事務(wù)的概念

InnoDB 存儲(chǔ)引擎中的事務(wù)完全符合 ACID 的特性:

  • 原子性(Atomicity)
    原子性指整個(gè)數(shù)據(jù)庫事務(wù)是不可分割的工作單位。只有使事務(wù)中所有的數(shù)據(jù)庫操作都執(zhí)行成功募疮,才算整個(gè)事務(wù)成功炫惩。事務(wù)中任何一個(gè) SQL 語句執(zhí)行失敗,已經(jīng)執(zhí)行成功的 SQL 語句也必須撤銷阿浓,數(shù)據(jù)庫狀態(tài)應(yīng)該退回到執(zhí)行事務(wù)前的狀態(tài)他嚷。

  • 一致性(Consistency)
    一致性指事務(wù)將數(shù)據(jù)庫從一種狀態(tài)轉(zhuǎn)變?yōu)橄乱环N一致的狀態(tài)。在事務(wù)開始之前和事務(wù)結(jié)束之后芭毙,數(shù)據(jù)庫的完整性約束沒有被破壞筋蓖。

  • 隔離性(Isolation)
    隔離性又叫做 并發(fā)控制(concurrency control)可串行化(serializability)退敦、鎖(locking)等粘咖。事務(wù)的隔離性要求每個(gè)讀寫事務(wù)的對(duì)象對(duì)其他事務(wù)的操作對(duì)象能相互分離,即該事務(wù)提交前對(duì)其他事務(wù)都不可見侈百,通常這使用鎖來實(shí)現(xiàn)瓮下。由定義可見,一般用于出發(fā)數(shù)據(jù)的的并發(fā)請(qǐng)求钝域。

  • 持久性(durability)
    事務(wù)一旦提交讽坏,其結(jié)果就是永久性的。即使發(fā)生宕機(jī)等故障网梢,數(shù)據(jù)庫也能將數(shù)據(jù)恢復(fù)震缭。但是只能從事務(wù)本身的角度來保證結(jié)果的永久性,一些外部原因的故障導(dǎo)致的數(shù)據(jù)丟失是無法保障的战虏。因此持久性保證事務(wù)系統(tǒng)的高可靠性(High Reliability)拣宰,而不是高可用性(High Availability)

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

事務(wù)的隔離性由鎖來實(shí)現(xiàn)党涕,關(guān)于 InnoDB 存儲(chǔ)引擎中的鎖,可以參考本人之前的一篇文章巡社。
原子性膛堤、一致性、持久性通過數(shù)據(jù)庫的 redo log 和 undo log 來完成晌该。redo log 稱為重做日志肥荔,用來保證事務(wù)的原子性和持久性。undo log 用來保證事務(wù)的一致性朝群。

redo

redo log 用來實(shí)現(xiàn)事務(wù)的持久性燕耿,記錄的是對(duì)于每個(gè)頁的修改
其由兩部分組成:

  • 內(nèi)存中的重做日志緩沖(redo log buffer)姜胖,因?yàn)槭谴嬖谟趦?nèi)存中誉帅,其是易失的;
  • 重做日志文件(redo log file)右莱,其是持久的

InnoDB 存儲(chǔ)引擎通過 Force Log at Commit 機(jī)制來實(shí)現(xiàn)事務(wù)的持久性蚜锨,即當(dāng)事務(wù)提交(COMMIT)使,必須先講該事務(wù)的所有日志寫入到重做日志文件進(jìn)行持久化慢蜓,待事務(wù)的 COMMIT 操作完成才算完成亚再。為了確保每次日志都寫入重做日志文件,在每次將重做日志緩沖寫入重做日志文件后晨抡,InnoDB 存儲(chǔ)引擎都需要調(diào)用一次 fsync 操作(確保重做日志從文件系統(tǒng)緩存寫入到磁盤)氛悬。

與 binlog 的區(qū)別

接觸過 MySQL 的同學(xué)應(yīng)該多少都會(huì)了解 binlog,會(huì)發(fā)現(xiàn) binlog 與 redo log 非常相似凄诞,都是記錄了對(duì)于數(shù)據(jù)操作的日志圆雁,為什么還要引入 redo log?binlog的兩個(gè)重要使用場景:

  1. MySQL 主從復(fù)制
  2. 數(shù)據(jù)恢復(fù)

但是兩者是存在非常大的區(qū)別的:

  • redo log 是在 InnoDB 存儲(chǔ)引擎層產(chǎn)生帆谍,binlog 是在 MySQL 數(shù)據(jù)庫的上層產(chǎn)生伪朽,不僅僅針對(duì) InnoDB 存儲(chǔ)引擎
  • 內(nèi)容形式不同。binlog 是一種邏輯日志汛蝙,記錄的是對(duì)應(yīng)的 SQL 語句或行的內(nèi)容烈涮;redo log 是物理格式日志,記錄的是對(duì)于每個(gè)頁(InnoDB 數(shù)據(jù)的存儲(chǔ)格式)的修改
  • 寫入磁盤的時(shí)間點(diǎn)不同窖剑。binlog 只在事務(wù)提交完成后進(jìn)行一次寫入坚洽;redo log 在事務(wù)進(jìn)行中不斷地被寫入。
  • redo log 空間是固定的西土,可重用讶舰;binlog 是追加寫,當(dāng)前文件寫完之后會(huì)開啟一個(gè)新文件繼續(xù)寫。

InnoDB 存儲(chǔ)引擎在啟動(dòng)時(shí)不管上次數(shù)據(jù)庫運(yùn)行時(shí)是否正常關(guān)閉跳昼,都會(huì)嘗試進(jìn)行恢復(fù)操作般甲。redo log 記錄的是物理日志,恢復(fù)速度比 binlog 要快很多鹅颊,而且InnoDB 恢復(fù)還進(jìn)行了一定程度的優(yōu)化-順序讀取及并行應(yīng)用redo log敷存。

group commit

事務(wù)的兩階段提交

  1. 修改內(nèi)存中事務(wù)對(duì)應(yīng)的信息,并且將日志寫入重做日志緩沖
  2. 調(diào)用 fsync 確保日志都從重做日志緩沖寫入磁盤

若事務(wù)為非只讀事務(wù)堪伍,則每次事務(wù)提交時(shí)需要進(jìn)行一次 fsync 操作锚烦,以此保證重做日志已經(jīng)寫入磁盤。

因?yàn)榇疟P的 fsync 性能時(shí)有限的帝雇,即上面的第二階段是個(gè)較慢的過程涮俄。但是當(dāng)有事務(wù)進(jìn)行第二階段提交時(shí),其他事務(wù)可以進(jìn)行第一階段的提交尸闸,正在提交的事務(wù)完成提交操作后禽拔,再次進(jìn)行第二階段,即 group commit 室叉,一次 fsync 可以刷新確保多個(gè)事務(wù)日志被寫入文件。

但是開啟 binlog 之后硫惕,group commit 功能就會(huì)失效茧痕。這是因?yàn)殚_啟 binlog 之后,需要保證binlog 和 redo log 的一致性恼除,二者之間使用了兩階段事務(wù)踪旷,步驟如下:

  1. 事務(wù)提交時(shí) InnoDB 存儲(chǔ)引擎進(jìn)行 prepare 操作
  2. MySQL 數(shù)據(jù)庫上層寫入 binlog
  3. InnoDB 存儲(chǔ)引擎將日志寫入 redo log
    1. 寫入redo log 緩沖
    2. 調(diào)用 fsync
      開啟 binlog 后 InnoDB 存儲(chǔ)引擎的提交過程.png

      為了保證 binlog 的寫入順序和 事務(wù)提交順序一致,MySQL 內(nèi)部使用了 prepare_commit_mutex 鎖豁辉,啟用該鎖后,步驟3.1 不可以在其他事務(wù)執(zhí)行 3.2 時(shí)進(jìn)行徽级,從而導(dǎo)致了 group commit 失效气破。

MySQL 5.6 采用 Binary Log Group Commit(BLGC) 來提高日志的寫入性能:
在 MySQL 數(shù)據(jù)庫上層進(jìn)行提交時(shí)首先按順序?qū)⑵浞湃胍粋€(gè)隊(duì)列中现使,隊(duì)列中的第一個(gè)事務(wù)稱為 leader,其他事務(wù)稱為 follower碳锈,leader 控制著 follower 的行為。

  1. Flush 階段欺抗,將每個(gè)事務(wù)的 binlog 寫入內(nèi)存中
  2. Sync 階段售碳,內(nèi)存中的 binlog 刷新到磁盤(如果隊(duì)列中有多個(gè)事務(wù),一次 fsync 操作就完成了多個(gè) binlog 的寫入)
  3. Commit 階段,leader 根據(jù)順序調(diào)用存儲(chǔ)引擎層事務(wù)的提交贸人,InnoDB 可以繼續(xù)使用 group commit

undo

undo log 用于將數(shù)據(jù)回滾到修改之前的樣子间景,因?yàn)榛貪L做的事情實(shí)際上是與之前相反的工作。所以灸姊,對(duì)于 INSERT 拱燃,undo log 會(huì)對(duì)應(yīng)一個(gè) DELETE 記錄;對(duì)于 DELETE力惯,畫丶do log 對(duì)應(yīng)一個(gè) INSERT碗誉;對(duì)于 UPDATE,undo log 對(duì)應(yīng)一個(gè)相反的 UPDATE父晶。
undo log 另一個(gè)作用是 MVCC哮缺,當(dāng)用戶讀取一行記錄時(shí),若該記錄已經(jīng)被其他事務(wù)占用甲喝,當(dāng)前事務(wù)可以通過 undo 讀取之前的行版本信息尝苇,從而實(shí)現(xiàn) 一致性非鎖定讀。

undo 存儲(chǔ)管理

InnoDB 存儲(chǔ)引擎對(duì) undo 的管理采用段(segment)的方式埠胖,rollback segment 稱為回滾段糠溜,每個(gè)回滾段記錄了 1024 個(gè) undo log segment。

在 InnoDB 存儲(chǔ)引擎中直撤,undo log 分為 insert undo log非竿、update undo log

  • insert undo log 是指在 insert 操作中產(chǎn)生的 undo log谋竖,因?yàn)?insert 操作只對(duì)本事務(wù)自身可見红柱,故該 undo log 可以在事務(wù)提交后直接刪除。
  • update undo log 記錄的是對(duì) delete 和 update 操作產(chǎn)生的 undo log蓖乘。該 undo log 可能需要提供 MVCC 機(jī)制锤悄,因此不能在事務(wù)提交時(shí)就進(jìn)行刪除,提交時(shí)放入 undo log 鏈表嘉抒,等待 purge 線程進(jìn)行最后的刪除零聚。

事務(wù)提交后并不能馬上刪除 undo log 及 undo log 所在的頁。因?yàn)榭赡苓€有其他事務(wù)需要通過 undo log 來得到行記錄之前的版本些侍。事務(wù)提交時(shí)將 undo log 放入一個(gè)鏈表中握牧,是否可以最終刪除 undo log 及 undo log 所在頁由 purge 線程來判斷。并且提交事務(wù)時(shí)娩梨,還會(huì)判斷 undo log 頁是否可以重用沿腰,如果可以重用,則會(huì)分配給后面的事務(wù)狈定。

purge

purge 操作用于最終完成 deleteupdate 操作颂龙。

InnoDB 存儲(chǔ)引擎有一個(gè) history 列表习蓬,根據(jù)事務(wù)提交的順序,將 undo log 進(jìn)行鏈接躲叼。InnoDB 存儲(chǔ)引擎先從 history list 中找 undo log企巢,然后再從 undo page 中找 undo log浪规,避免大量的隨機(jī)讀取操作,從而提高 purge 的效率誉裆。

redo log 用來保證事務(wù)的持久性足丢,undo log 用來幫助事務(wù)回滾以及 MVCC 的功能斩跌。redo log 基本上都是順序?qū)懙睦袒牛跀?shù)據(jù)運(yùn)行時(shí)不需要對(duì) redo log 的文件進(jìn)行讀取操作卿闹,而 undo log 是需要進(jìn)行隨機(jī)讀取的锻霎。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末旋恼,一起剝皮案震驚了整個(gè)濱河市冰更,隨后出現(xiàn)的幾起案子蜀细,更是在濱河造成了極大的恐慌戈盈,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件痊夭,死亡現(xiàn)場離奇詭異她我,居然都是意外死亡迫横,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門合蔽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拴事,“玉大人刃宵,你說我怎么就攤上這事徘公」孛妫” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵捂齐,是天一觀的道長奠宜。 經(jīng)常有香客問我压真,道長蘑险,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任嘴高,我火速辦了婚禮拴驮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宽气。我一直安慰自己萄涯,他們只是感情好唆鸡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布争占。 她就那樣靜靜地躺著臂痕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪姆怪。 梳的紋絲不亂的頭發(fā)上澡绩,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天溪掀,我揣著相機(jī)與錄音,去河邊找鬼蛮浑。 笑死沮稚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的障般。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼藐石,長吁一口氣:“原來是場噩夢啊……” “哼于微!你這毒婦竟也來了株依?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤恋腕,失蹤者是張志新(化名)和其女友劉穎荠藤,沒想到半個(gè)月后呆万,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谋减,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡庄吼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年总寻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了渐行。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铸董。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蕴忆,死狀恐怖套鹅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卓鹿,我是刑警寧澤减牺,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布肥隆,位于F島的核電站稚失,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏吸占。R本人自食惡果不足惜矾屯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一件蚕、第九天 我趴在偏房一處隱蔽的房頂上張望产禾。 院中可真熱鬧排作,春花似錦、人聲如沸亚情。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽楞件。三九已至衫生,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間土浸,已是汗流浹背罪针。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留栅迄,地道東北人站故。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓皆怕,卻偏偏與公主長得像毅舆,于是被迫代替她去往敵國和親岂津。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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