MySQL之事務(wù)

1沼溜、ACID

事務(wù)是數(shù)據(jù)庫(kù)區(qū)別于文件系統(tǒng)的重要特性之一潮梯。

InnoDB的事務(wù)完全符合ACID特性骗灶。

  • 原子性(Atomicity):操作過(guò)程不可分割,要么全部成功秉馏,要么全部失敗
  • 一致性(Consistency):完整性約束不被破壞
  • 隔離性(Isolution):事務(wù)提交前對(duì)其他事務(wù)不可見(jiàn)
  • 持久性(Durability):事務(wù)一旦提交耙旦,其結(jié)果就是永久性的

In弄DB中的ACID特性依靠如下機(jī)制實(shí)現(xiàn):

  • 隔離性由鎖來(lái)實(shí)現(xiàn);
  • 原子性和持久性由redo log來(lái)實(shí)現(xiàn)萝究;
  • 一致性由undo log來(lái)實(shí)現(xiàn)免都。

2、隔離級(jí)別

事務(wù)的隔離性是數(shù)據(jù)庫(kù)處理數(shù)據(jù)的幾大基礎(chǔ)之一帆竹,而隔離級(jí)別其實(shí)就是提供給用戶用于在性能和可靠性做出選擇和權(quán)衡的配置項(xiàng)绕娘。

InnoDB 遵循了 SQL:1992 標(biāo)準(zhǔn)中的四種隔離級(jí)別:

  • RAED UNCOMMITED:使用查詢語(yǔ)句不會(huì)加鎖,可能會(huì)讀到未提交的行(Dirty Read)栽连;
  • READ COMMITED:只對(duì)記錄加記錄鎖险领,而不會(huì)在記錄之間加間隙鎖,所以允許新的記錄插入到被鎖定記錄的附近秒紧,所以再多次使用查詢語(yǔ)句時(shí)绢陌,可能得到不同的結(jié)果(Non-Repeatable Read);
  • REPEATABLE READ:多次讀取同一范圍的數(shù)據(jù)會(huì)返回第一次查詢的快照噩茄,不會(huì)返回不同的數(shù)據(jù)行下面,但是可能發(fā)生幻讀(Phantom Read);
  • SERIALIZABLE:InnoDB 隱式地將全部的查詢語(yǔ)句加上共享鎖绩聘,解決了幻讀的問(wèn)題沥割;

MySQL 中默認(rèn)的事務(wù)隔離級(jí)別就是 REPEATABLE READ耗啦,但是它通過(guò) Next-Key 鎖也能夠在某種程度上解決幻讀的問(wèn)題。

接下來(lái)机杜,我們將數(shù)據(jù)庫(kù)中創(chuàng)建如下的表并通過(guò)個(gè)例子來(lái)展示在不同的事務(wù)隔離級(jí)別之下帜讲,會(huì)發(fā)生什么樣的問(wèn)題:

CREATE TABLE test(
    id INT NOT NULL,
    UNIQUE(id)
);

2.1 臟讀

當(dāng)事務(wù)的隔離級(jí)別為 READ UNCOMMITED 時(shí),我們?cè)?SESSION 2 中插入的未提交數(shù)據(jù)在 SESSION 1 中是可以訪問(wèn)的椒拗。

1.png

2.2 不可重復(fù)讀

當(dāng)事務(wù)的隔離級(jí)別為 READ COMMITED 時(shí)似将,雖然解決了臟讀的問(wèn)題,但是如果在 SESSION 1 先查詢了一個(gè)范圍的數(shù)據(jù)蚀苛,在這之后 SESSION 2 中插入一條數(shù)據(jù)并且提交了修改在验,在這時(shí),如果 SESSION 1 中再次使用相同的查詢語(yǔ)句堵未,就會(huì)發(fā)現(xiàn)兩次查詢的結(jié)果不一樣腋舌。

2.png

不可重復(fù)讀的原因就是,在 READ COMMITED 的隔離級(jí)別下渗蟹,存儲(chǔ)引擎不會(huì)在查詢記錄時(shí)添加間隙鎖块饺,鎖定 id < 5 這個(gè)范圍。

2.3 幻讀

重新開(kāi)啟了兩個(gè)會(huì)話 SESSION 1SESSION 2雌芽,在 SESSION 1 中我們查詢?nèi)淼男畔⑹诩瑁瑳](méi)有得到任何記錄;在 SESSION 2 中向表中插入一條數(shù)據(jù)并提交世落;由于 REPEATABLE READ 的原因淮腾,再次查詢?nèi)淼臄?shù)據(jù)時(shí),我們獲得到的仍然是空集岛心,但是在向表中插入同樣的數(shù)據(jù)卻出現(xiàn)了錯(cuò)誤来破。

3.png

這種現(xiàn)象在數(shù)據(jù)庫(kù)中就被稱作幻讀,雖然我們使用查詢語(yǔ)句得到了一個(gè)空的集合忘古,但是插入數(shù)據(jù)時(shí)卻得到了錯(cuò)誤徘禁,好像之前的查詢是幻覺(jué)一樣。

在標(biāo)準(zhǔn)的事務(wù)隔離級(jí)別中髓堪,幻讀是由更高的隔離級(jí)別 SERIALIZABLE 解決的送朱,但是它也可以通過(guò) MySQL 提供的 Next-Key 鎖解決:

4.png

REPERATABLE READREAD UNCOMMITED 其實(shí)是矛盾的,如果保證了前者就看不到已經(jīng)提交的事務(wù)干旁,如果保證了后者驶沼,就會(huì)導(dǎo)致兩次查詢的結(jié)果不同,MySQL 為我們提供了一種折中的方式争群,能夠在 REPERATABLE READ 模式下加鎖訪問(wèn)已經(jīng)提交的數(shù)據(jù)回怜,其本身并不能解決幻讀的問(wèn)題,而是通過(guò)文章前面提到的 Next-Key 鎖來(lái)解決换薄。

3玉雾、重做日志(redo log)

3.1 write-ahead logging

預(yù)寫(xiě)式日志(write-ahead logging翔试,WAL ),是一種實(shí)現(xiàn)事務(wù)日志的標(biāo)準(zhǔn)方法复旬,其中心思想是對(duì)數(shù)據(jù)文件的修改必須發(fā)生在這些修改已經(jīng)記錄了日志之后垦缅。

如果遵循這個(gè)過(guò)程,那么就不需要在每次事務(wù)提交的時(shí)候都把數(shù)據(jù)頁(yè)沖刷到磁盤(pán)驹碍,因?yàn)榧幢愠霈F(xiàn)宕機(jī)的情況壁涎, 我們也可以用日志來(lái)恢復(fù)數(shù)據(jù)庫(kù):任何尚未附加到數(shù)據(jù)頁(yè)的記錄都將先從日志記錄中重做(這叫向前滾動(dòng)恢復(fù),也叫做 redo)志秃。

使用 WAL 的第一個(gè)主要的好處就是顯著地減少了磁盤(pán)寫(xiě)的次數(shù)怔球。 因?yàn)樵谌罩咎峤坏臅r(shí)候只有日志文件需要沖刷到磁盤(pán);而不是事務(wù)修改的所有數(shù)據(jù)文件洽损。 在多用戶環(huán)境里庞溜,許多事務(wù)的提交可以用日志文件的一次 fsync() 來(lái)完成。而且碑定,日志文件是順序?qū)懙?/strong>, 因此同步日志的開(kāi)銷要遠(yuǎn)比同步數(shù)據(jù)頁(yè)的開(kāi)銷要小又官。 這一點(diǎn)對(duì)于許多小事務(wù)對(duì)磁盤(pán)的隨機(jī)寫(xiě)入更是如此延刘。

3.2 基本概念

MySQL作為一個(gè)存儲(chǔ)系統(tǒng),為了保證數(shù)據(jù)的可靠性六敬,最終得落盤(pán)碘赖;又為了數(shù)據(jù)寫(xiě)入的速度,需要引入基于內(nèi)存的“緩沖池”外构。也就是說(shuō)普泡,數(shù)據(jù)是先緩存在緩沖池中,然后再以某種方式刷新到磁盤(pán)审编,在某個(gè)時(shí)間段之內(nèi)撼班,緩存中的數(shù)據(jù)與磁盤(pán)的數(shù)是不一致的,如果這個(gè)時(shí)候宕機(jī)會(huì)導(dǎo)致緩存數(shù)據(jù)的丟失垒酬。

引入redo log的目的就是為了防止以上問(wèn)題的發(fā)生砰嘁。

當(dāng)向InnoDB寫(xiě)用戶數(shù)據(jù)時(shí),先寫(xiě)redo log勘究,然后redo log根據(jù)一定的規(guī)則持久化到磁盤(pán)矮湘,變成redo log file,用戶數(shù)據(jù)則在buffer中(比如數(shù)據(jù)頁(yè)口糕、索引頁(yè))缅阳。如果發(fā)生宕機(jī),重啟后則讀取磁盤(pán)上的 redo log file 進(jìn)行數(shù)據(jù)的恢復(fù)景描。

從這個(gè)角度來(lái)說(shuō)十办,InnoDB事務(wù)的持久性是通過(guò) redo log 來(lái)實(shí)現(xiàn)的秀撇。

下面以一個(gè)更新事務(wù)為例,宏觀上把握redo log 流轉(zhuǎn)過(guò)程橘洞,如下圖所示:

5.png
  • 第一步:先將原始數(shù)據(jù)從磁盤(pán)中讀入內(nèi)存中來(lái)捌袜,修改數(shù)據(jù)的內(nèi)存拷貝
  • 第二步:生成一條重做日志并寫(xiě)入redo log buffer,記錄的是數(shù)據(jù)被修改后的值
  • 第三步:當(dāng)事務(wù)commit時(shí)炸枣,將redo log buffer中的內(nèi)容刷新到 redo log file虏等,對(duì) redo log file采用追加寫(xiě)的方式
  • 第四步:定期將內(nèi)存中修改的數(shù)據(jù)刷新到磁盤(pán)中

redo log包括兩部分:

  • 內(nèi)存中的日志緩沖(redo log buffer),該部分日志是易失性的
  • 磁盤(pán)上的重做日志文件(redo log file)适肠,該部分日志是持久的

InnoDB通過(guò)force log at commit機(jī)制實(shí)現(xiàn)事務(wù)的持久性霍衫,即在事務(wù)提交的時(shí)候,必須先將該事務(wù)的所有事務(wù)日志寫(xiě)入到磁盤(pán)上的redo log file和undo log file中進(jìn)行持久化侯养。

為了確保每次日志都能寫(xiě)入到事務(wù)日志文件中敦跌,在每次將log buffer中的日志寫(xiě)入日志文件的過(guò)程中都會(huì)調(diào)用一次操作系統(tǒng)的fsync操作(即fsync()系統(tǒng)調(diào)用)。因?yàn)镸ySQL是工作在用戶空間的逛揩,MySQL的log buffer處于用戶空間的內(nèi)存中柠傍。要寫(xiě)入到磁盤(pán)上的log file中,中間還要經(jīng)過(guò)操作系統(tǒng)內(nèi)核空間的os buffer辩稽,調(diào)用fsync()的作用就是將OS buffer中的日志刷到磁盤(pán)上的log file中惧笛。

也就是說(shuō),從redo log buffer寫(xiě)日志到磁盤(pán)的redo log file中逞泄,過(guò)程如下:

6.png

redo log buffer 刷新到磁盤(pán)的時(shí)機(jī)由參數(shù) InnoDB_flush_log_at_trx_commit 控制患整,默認(rèn)為1:

  • 0: 事務(wù)提交時(shí)不進(jìn)行寫(xiě)入redo log操作,而是依靠master線程周期性的刷盤(pán)來(lái)保證喷众。由于master線程每1秒進(jìn)行一次redo log的fsync操作各谚,因此實(shí)例崩潰后最多丟失1秒鐘內(nèi)的事務(wù)
  • 1: 事務(wù)提交時(shí)必須調(diào)用一次 fsync 操作,這種方式即使系統(tǒng)崩潰也不會(huì)丟失任何數(shù)據(jù)到千,但是因?yàn)槊看翁峤欢紝?xiě)入磁盤(pán)昌渤,IO的性能較差。該值是InnoDB的默認(rèn)值
  • 2: 在事務(wù)提交時(shí)只保證將redo log buffer寫(xiě)到系統(tǒng)的os buffer中父阻,不進(jìn)行fsync操作愈涩,因此如果MySQL數(shù)據(jù)庫(kù)宕機(jī)時(shí) 不會(huì)丟失事務(wù),但操作系統(tǒng)宕機(jī)則可能丟失事務(wù)

3.3 兩次寫(xiě)

當(dāng)發(fā)生數(shù)據(jù)庫(kù)宕機(jī)時(shí)加矛,可能InnoDB存儲(chǔ)引擎正在寫(xiě)入某個(gè)頁(yè)到表中履婉,而這個(gè)頁(yè)只寫(xiě)了一部分,比如16KB的頁(yè)斟览,只寫(xiě)了前4KB毁腿,之后就發(fā)生了宕機(jī),這種情況被稱為部分寫(xiě)失效(partial page write)。

部分寫(xiě)失效的問(wèn)題已烤,依靠重做日志無(wú)法恢復(fù)鸠窗,因?yàn)橹刈鋈罩臼腔谄屏康奈锢聿僮鳌@缈杈浚瑢?xiě)'aaaa'記錄到偏移量800的位置稍计,如果這個(gè)頁(yè)本身已經(jīng)發(fā)生了損壞,再對(duì)其進(jìn)行重做是沒(méi)有意義的裕循。這就是說(shuō)臣嚣,在使用重做日志前,用戶需要一個(gè)頁(yè)的副本剥哑,當(dāng)寫(xiě)入失效發(fā)生時(shí)硅则,先通過(guò)頁(yè)的副本來(lái)還原該頁(yè),再進(jìn)行重做株婴,這就是doublewrite怎虫。

下面是兩次寫(xiě)的原理圖:

6-1.png

doublewrite由兩部分組成:

  • 內(nèi)存中的doublewrite buffer,大小為2MB
  • 物理磁盤(pán)上共享表空間中連續(xù)的128個(gè)頁(yè)困介,即2個(gè)區(qū)(extent)乔遮,大小同樣為2MB

當(dāng)刷新緩沖池臟頁(yè)時(shí)鲫凶,并不直接寫(xiě)到數(shù)據(jù)文件中鳞绕,而是按照下面的路程執(zhí)行:

  1. 拷貝至內(nèi)存中的兩次寫(xiě)緩沖區(qū)氧急。
  2. 從兩次寫(xiě)緩沖區(qū)分兩次寫(xiě)入磁盤(pán)共享表空間中,每次1MB
  3. 待第2步完成后八回,再將兩次寫(xiě)緩沖區(qū)寫(xiě)入數(shù)據(jù)文件

這樣就可以解決上文提到的部分寫(xiě)失效的問(wèn)題,因?yàn)樵诖疟P(pán)共享表空間中已有數(shù)據(jù)頁(yè)副本拷貝驾诈,如果數(shù)據(jù)庫(kù)在頁(yè)寫(xiě)入數(shù)據(jù)文件的過(guò)程中宕機(jī)缠诅,在實(shí)例恢復(fù)時(shí),可以從共享表空間中找到該頁(yè)副本乍迄,將其拷貝覆蓋原有的數(shù)據(jù)頁(yè)管引,再應(yīng)用重做日志即可。

其中第2步是額外的性能開(kāi)銷闯两,但由于磁盤(pán)共享表空間是連續(xù)的褥伴,因此開(kāi)銷不是很大⊙牵可以通過(guò)參數(shù)skip_innodb_doublewrite禁用兩次寫(xiě)功能重慢,默認(rèn)是開(kāi)啟的。

3.4 LSN

緩存中未刷到磁盤(pán)的數(shù)據(jù)稱為臟數(shù)據(jù)(dirty data)逊躁。由于數(shù)據(jù)和日志都以頁(yè)的形式存在似踱,所以臟頁(yè)包含臟數(shù)據(jù)和臟日志。

在InnoDB中,由一系列的規(guī)則來(lái)判斷是否到達(dá)了checkpoint核芽,到達(dá)后會(huì)將緩存中的臟數(shù)據(jù)頁(yè)和臟日志頁(yè)都刷到磁盤(pán)囚戚。

LSN稱為日志的邏輯序列號(hào)(log sequence number),隨著日志的寫(xiě)入而逐漸增大轧简。根據(jù)LSN驰坊,可以獲取到幾個(gè)有用的信息:

  • 數(shù)據(jù)頁(yè)的版本信息。
  • 寫(xiě)入的日志總量哮独,通過(guò)LSN開(kāi)始號(hào)碼和結(jié)束號(hào)碼可以計(jì)算出寫(xiě)入的日志量拳芙。
  • 可知道檢查點(diǎn)的位置。

可以通過(guò)show engine innodb status命令查看LSN的情況:

mysql> show engine innodb status\G;
*************************** 1. row ***************************
...
---
LOG
---
Log sequence number 2611354
Log flushed up to   2611354
Pages flushed up to 2611354
Last checkpoint at  2611345
0 pending log flushes, 0 pending chkp writes
10 log i/o's done, 0.09 log i/o's/second
...
  • Log sequence number表示當(dāng)前的LSN,
  • Log flushed up to表示刷新到重做日志文件的LSN
  • Pages flushed up to表示寫(xiě)入磁盤(pán)的dirty page 上的LSN
  • Last checkpoint at表示寫(xiě)入磁盤(pán)的checkpoint上的LSN

3.5 恢復(fù)過(guò)程

在啟動(dòng)InnoDB的時(shí)候借嗽,不管上次是正常關(guān)閉還是異常關(guān)閉态鳖,總是會(huì)進(jìn)行恢復(fù)操作。

因?yàn)?strong>redo log記錄的是數(shù)據(jù)頁(yè)的物理變化恶导,因此恢復(fù)的時(shí)候速度比邏輯日志(如二進(jìn)制日志)要快很多浆竭。而且,InnoDB自身也做了一定程度的優(yōu)化惨寿,讓恢復(fù)速度變得更快邦泄。

重啟InnoDB時(shí),checkpoint表示已經(jīng)完整刷到磁盤(pán)上data page上的LSN裂垦,因此恢復(fù)時(shí)僅需要恢復(fù)從checkpoint開(kāi)始的日志部分顺囊。例如,當(dāng)數(shù)據(jù)庫(kù)在上一次checkpoint的LSN為10000時(shí)宕機(jī)蕉拢,且事務(wù)是已經(jīng)提交過(guò)的狀態(tài)特碳。啟動(dòng)數(shù)據(jù)庫(kù)時(shí)會(huì)檢查磁盤(pán)中數(shù)據(jù)頁(yè)的LSN,如果數(shù)據(jù)頁(yè)的LSN小于日志中的LSN晕换,則會(huì)從檢查點(diǎn)開(kāi)始恢復(fù)午乓。

還有一種情況,在宕機(jī)前正處于checkpoint的刷盤(pán)過(guò)程闸准,且數(shù)據(jù)頁(yè)的刷盤(pán)進(jìn)度超過(guò)了日志頁(yè)的刷盤(pán)進(jìn)度益愈。這時(shí)候一宕機(jī),數(shù)據(jù)頁(yè)中記錄的LSN就會(huì)大于日志頁(yè)中的LSN夷家,在重啟的恢復(fù)過(guò)程中會(huì)檢查到這一情況蒸其,這時(shí)超出日志進(jìn)度的部分將不會(huì)重做,因?yàn)檫@本身就表示已經(jīng)做過(guò)的事情库快,無(wú)需再重做摸袁。

另外,事務(wù)日志具有冪等性缺谴,所以多次操作得到同一結(jié)果的行為在日志中只記錄一次但惶。而二進(jìn)制日志不具有冪等性耳鸯,多次操作會(huì)全部記錄下來(lái),在恢復(fù)的時(shí)候會(huì)多次執(zhí)行二進(jìn)制日志中的記錄膀曾,速度就慢得多县爬。例如,某記錄中id初始值為2添谊,通過(guò)update將值設(shè)置為了3财喳,后來(lái)又設(shè)置成了2,在事務(wù)日志中記錄的將是無(wú)變化的頁(yè)斩狱,根本無(wú)需恢復(fù)耳高;而二進(jìn)制會(huì)記錄下兩次update操作,恢復(fù)時(shí)也將執(zhí)行這兩次update操作所踊,速度比事務(wù)日志恢復(fù)更慢泌枪。

4、回滾日志(undo log)

4.1 基本概念

重做日志記錄了事務(wù)的行為秕岛,可以很好地通過(guò)其進(jìn)行"重做"碌燕。但是事務(wù)有時(shí)還需要撤銷,這是就需要undo继薛。undo與redo正好相反修壕,對(duì)于數(shù)據(jù)庫(kù)進(jìn)行修改時(shí),數(shù)據(jù)庫(kù)不但會(huì)產(chǎn)生redo遏考,而且還會(huì)產(chǎn)生一定量的undo慈鸠。如果因?yàn)槟承┰驅(qū)е率聞?wù)失敗或回滾了,可以借助該undo進(jìn)行回滾灌具。

undo log有兩個(gè)作用:

  • 提供回滾

    當(dāng)事務(wù)回滾時(shí)青团,或者數(shù)據(jù)庫(kù)崩潰后重啟,可以利用undo日志咖楣,即舊版本數(shù)據(jù)壶冒,撤銷未提交事務(wù)對(duì)數(shù)據(jù)庫(kù)產(chǎn)生的影響。

  • 多版本控制(MVCC)

    當(dāng)讀取的某一行被其他事務(wù)鎖定時(shí)截歉,它可以從undo log中分析出該行記錄以前的數(shù)據(jù)是什么,從而提供該行版本信息烟零,讓用戶實(shí)現(xiàn)非鎖定一致性讀取瘪松。

與redo不同的是,redo存放在重做日志文件中锨阿,undo存放在數(shù)據(jù)庫(kù)內(nèi)部的一個(gè)特殊的段(segment)中宵睦,稱為undo段(undo segment),undo段位于共享表空間內(nèi)墅诡。InnoDB對(duì)undo的管理同樣采用段的方式壳嚎,稱為rollback segment。每個(gè)回滾段記錄了1024個(gè)undo段。

undo log和redo log記錄物理日志不一樣烟馅,它是邏輯日志说庭。可以認(rèn)為當(dāng)delete一條記錄時(shí)郑趁,undo log中會(huì)記錄一條對(duì)應(yīng)的insert記錄刊驴,反之亦然,當(dāng)update一條記錄時(shí)寡润,它記錄一條對(duì)應(yīng)相反的update記錄捆憎。

另外,undo log也會(huì)產(chǎn)生redo log梭纹,因?yàn)閡ndo log也要實(shí)現(xiàn)持久性保護(hù)躲惰。

4.2 purge

purge線程兩個(gè)主要作用是:清理undo頁(yè)和清除page里面帶有Delete_Bit標(biāo)識(shí)的數(shù)據(jù)行。

對(duì)插入变抽、更新础拨、刪除操作來(lái)說(shuō),purge操作的作用如下:

  • insert

    因?yàn)閕nsert操作的記錄瞬沦,只對(duì)事務(wù)本身可見(jiàn)太伊,對(duì)其他事務(wù)不可見(jiàn),所以不需要保證MVCC逛钻。故該undo log可以在事務(wù)提交后直接刪除僚焦,不需要進(jìn)行purge操作。

  • update

    該undo log可能需要服務(wù)MVCC曙痘,因此不能再事務(wù)提交時(shí)就進(jìn)行刪除芳悲。提交時(shí)放入undo log鏈表,等待purge線程進(jìn)行最后的刪除

  • delete

    與update類似边坤,delete的undo log也可能需要服務(wù)MVCC名扛。在InnoDB中,事務(wù)中的delete操作實(shí)際上并不是真正的刪除掉數(shù)據(jù)行茧痒,而是做了個(gè)標(biāo)記肮韧,真正的刪除工作需要后臺(tái)purge線程去完成。

5旺订、分布式事務(wù)

InnoDB通過(guò)XA事務(wù)來(lái)支持分布式事務(wù)的實(shí)現(xiàn)弄企。

XA事務(wù)由一個(gè)或多個(gè)資源管理器(Resource Manager)、一個(gè)事務(wù)管理器(Transaction Manager)以及一個(gè)應(yīng)用程序組成:

  • 資源管理器:提供訪問(wèn)事務(wù)資源的方法区拳。通常一個(gè)數(shù)據(jù)就是一個(gè)資源管理器
  • 事務(wù)管理器:協(xié)調(diào)參與全局事務(wù)中的各個(gè)事務(wù)拘领。需要和參與全局事務(wù)的所有資源管理器進(jìn)行通信
  • 應(yīng)用程序:定義事務(wù)的邊界,指定全局事務(wù)中的操作
7.png

分布式事務(wù)使用兩段式提交(two-phase commit)的方式樱调。

  • 第一個(gè)階段约素,所有參與全局事務(wù)的節(jié)點(diǎn)都開(kāi)始準(zhǔn)備届良,告訴事務(wù)管理器它們準(zhǔn)備好提交了。
  • 第二個(gè)階段圣猎,事務(wù)管理器告訴資源管理器執(zhí)行rollback或者commit士葫,如果任何一個(gè)節(jié)點(diǎn)顯示不能commit,那么所有的節(jié)點(diǎn)就得全部rollback样漆。

在MySQL中還存在一種內(nèi)部XA事務(wù)为障,存在于存儲(chǔ)引擎與插件之間,又或者存儲(chǔ)引擎與存儲(chǔ)引擎之間放祟。

最常見(jiàn)的內(nèi)部XA事務(wù)是binlog與InnoDB之間鳍怨。 由于復(fù)制的需要,因此目前絕大多數(shù)的數(shù)據(jù)庫(kù)都開(kāi)啟了 binlog 功能跪妥。在事務(wù)提交時(shí)鞋喇,先寫(xiě)二進(jìn)制日志,再寫(xiě) InnoDB 存儲(chǔ)引擎的重做日志眉撵。對(duì)上述兩個(gè)操作的要求也是原子的侦香,即二進(jìn)制日志和重做日志必須同時(shí)寫(xiě)入。若二進(jìn)制日志先寫(xiě)了纽疟,而在寫(xiě)入 InnoDB 存儲(chǔ)引擎時(shí)發(fā)生了者機(jī)罐韩,那么 slave 可能會(huì)接收到 master 傳過(guò)去的二進(jìn)制日志并執(zhí)行,最終導(dǎo)致了主從不一致的情況污朽。

8.png

在上圖中散吵,如果執(zhí)行完第二步,未執(zhí)行第三步時(shí) MySQL 數(shù)據(jù)庫(kù)發(fā)生了宕機(jī) 蟆肆,則會(huì)發(fā)生主從不一致的情況矾睦。為了解決這個(gè)問(wèn)題,MySQL 數(shù)據(jù)庫(kù)在 binlog 與 InnoDB 存儲(chǔ)引擎之間采用XA事務(wù)炎功。當(dāng)事務(wù)提交時(shí)枚冗,InnoDB 存儲(chǔ)引擎會(huì)先做一個(gè)PREPARE操作,將事務(wù)的xid寫(xiě)入蛇损,接著進(jìn)行二進(jìn)制日志的寫(xiě)入赁温。

9.png

如果在 InnoDB 存儲(chǔ)引擎提交前,MySQL 數(shù)據(jù)庫(kù)宕機(jī)了淤齐,那么 MySQL 數(shù)據(jù)庫(kù)在重啟后會(huì)先檢查準(zhǔn)備的 UXID 事務(wù)是否已經(jīng)提交束世,若沒(méi)有,則在存儲(chǔ)引擎層再進(jìn)行一次提交操作床玻。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市沉帮,隨后出現(xiàn)的幾起案子锈死,更是在濱河造成了極大的恐慌贫堰,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件待牵,死亡現(xiàn)場(chǎng)離奇詭異其屏,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)缨该,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)偎行,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人贰拿,你說(shuō)我怎么就攤上這事蛤袒。” “怎么了膨更?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵妙真,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我荚守,道長(zhǎng)珍德,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任矗漾,我火速辦了婚禮锈候,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘敞贡。我一直安慰自己泵琳,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布嫡锌。 她就那樣靜靜地躺著虑稼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪势木。 梳的紋絲不亂的頭發(fā)上蛛倦,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音啦桌,去河邊找鬼溯壶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛甫男,可吹牛的內(nèi)容都是我干的且改。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼板驳,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼又跛!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起若治,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤慨蓝,失蹤者是張志新(化名)和其女友劉穎感混,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體礼烈,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡弧满,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了此熬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片庭呜。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖犀忱,靈堂內(nèi)的尸體忽然破棺而出募谎,到底是詐尸還是另有隱情,我是刑警寧澤峡碉,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布近哟,位于F島的核電站,受9級(jí)特大地震影響鲫寄,放射性物質(zhì)發(fā)生泄漏吉执。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一地来、第九天 我趴在偏房一處隱蔽的房頂上張望戳玫。 院中可真熱鬧,春花似錦未斑、人聲如沸咕宿。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)府阀。三九已至,卻和暖如春芽突,著一層夾襖步出監(jiān)牢的瞬間试浙,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工寞蚌, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留田巴,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓挟秤,卻偏偏與公主長(zhǎng)得像壹哺,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子艘刚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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