4. undo日志
undo log(撤銷(xiāo)日志或回滾日志)記錄了事務(wù)發(fā)生之前的數(shù)據(jù)狀態(tài),分為insert undo log和update undo log。
如果修改數(shù)據(jù)時(shí)出現(xiàn)異常,可以用 undo log來(lái)實(shí)現(xiàn)回滾操作(保持原子性)??梢岳斫鉃閡ndo日志記錄的是反向的操作,比如INSERT操作會(huì)記錄DELETE,UPDATE會(huì)記錄UPDATE之前的值,和redo日志記錄在哪個(gè)物理頁(yè)面做了什么操作不同,所以這是一種邏輯格式的日志。
undo日志和redo日志與事務(wù)密切相關(guān),被統(tǒng)稱(chēng)為「事務(wù)日志」。

關(guān)于undo日志,我們目前只需要了解這么多即可
5. SQL更新語(yǔ)句的執(zhí)行總結(jié)——初版
有了事務(wù)日志之后,我們來(lái)簡(jiǎn)單總結(jié)一下更新操作的流程,這是一個(gè)簡(jiǎn)化的過(guò)程。
name 原值是chanmufeng。
update t_user_innodb set name ='chanmufeng1994' where id = 1;
- 事務(wù)開(kāi)始,從內(nèi)存(Buffer Pool)或磁盤(pán)取到包含這條數(shù)據(jù)的數(shù)據(jù)頁(yè),返回給 Server 的執(zhí)行器;
- Server 的執(zhí)行器修改數(shù)據(jù)頁(yè)的這一行數(shù)據(jù)的值為 chanmufeng1994;
- 記錄 name=chanmufeng 到undo log;
- 記錄 name=chanmufeng1994到redo log;
- 調(diào)用存儲(chǔ)引擎接口,記錄數(shù)據(jù)頁(yè)到Buffer Pool(修改 name=penyuyan);
- 事務(wù)提交。
6. binlog日志
之前我們講過(guò),從MySQL整體架構(gòu)來(lái)看,其實(shí)可以分成兩部分
- Server 層,它主要做的是 MySQL功能層面的事情,比如處理連接、解析優(yōu)化等;
- 存儲(chǔ)引擎層,負(fù)責(zé)存儲(chǔ)相關(guān)的具體事宜。
redo日志是InnoDB存儲(chǔ)引擎特有的日志,而Server層也有自己的日志,稱(chēng)為 binlog(歸檔日志),它可以被所有存儲(chǔ)引擎使用。
6.1 為什么有了redo日志還需要 binlog?
我想你可能會(huì)問(wèn)出這個(gè)問(wèn)題,實(shí)際上,更準(zhǔn)確的問(wèn)法是為什么有了binlog還需要有redo日志?主要有以下幾個(gè)原因。
- 因?yàn)樽铋_(kāi)始MySQL里并沒(méi)有InnoDB存儲(chǔ)引擎。MySQL自帶的引擎是MyISAM,但是 MyISAM沒(méi)有崩潰恢復(fù)的能力,InnoDB后來(lái)以插件的形式被引入,順便帶來(lái)了redo日志;
- binlog日志是用來(lái)歸檔的,binlog以事件的形式記錄了所有的 DDL和 DML 語(yǔ)句(因?yàn)樗涗浀氖遣僮鞫皇?數(shù)據(jù)值,屬于邏輯日志),但是不具備宕機(jī)恢復(fù)的功能,因?yàn)榭赡軟](méi)有來(lái)得及刷新臟頁(yè),造成臟頁(yè)數(shù)據(jù)的丟失,而這些操作也沒(méi)有保存到binlog中從而造成數(shù)據(jù)丟失;
- binlog記錄的是關(guān)于一個(gè)事務(wù)的具體操作內(nèi)容,即該日志是邏輯日志。而redo日志記錄的是關(guān)于每個(gè)頁(yè)的更改的物理情況。功能壓根不是一回事兒。
6.2 binlog日志的作用
6.2.1 主從復(fù)制
binlog是實(shí)現(xiàn)MySQL主從復(fù)制功能的核心組件。
master節(jié)點(diǎn)會(huì)將所有的寫(xiě)操作記錄到binlog中,slave節(jié)點(diǎn)會(huì)有專(zhuān)門(mén)的I/O線(xiàn)程讀取master節(jié)點(diǎn)的binlog,將寫(xiě)操作同步到當(dāng)前所在的slave節(jié)點(diǎn)。

6.2.2 數(shù)據(jù)恢復(fù)
假如你在閱讀這篇文章的時(shí)候覺(jué)得我寫(xiě)得實(shí)在太好,拍案叫絕的時(shí)候一不小心把公司的數(shù)據(jù)庫(kù)給刪了,你該怎么做才能恢復(fù)到你刪庫(kù)之前的那個(gè)時(shí)刻的狀態(tài)?
這個(gè)時(shí)候就要用到binlog了,前提是binlog沒(méi)有被刪除,否則,神仙也救不了你了。
通常情況下,公司會(huì)定期對(duì)數(shù)據(jù)庫(kù)進(jìn)行全量備份,可能隔一個(gè)月,一周,甚至可能每天都備份一次。運(yùn)氣好的話(huà)你可以使用前一天的全量備份,恢復(fù)到前一天的某時(shí)刻狀態(tài)(或者一周、一月之前),然后從全量備份的時(shí)刻開(kāi)始,從binlog中提取該時(shí)刻之后(前提是你的binlog里面存放了這段時(shí)間的日志)的所有寫(xiě)操作(當(dāng)然,你得過(guò)濾掉你的刪庫(kù)操作),然后進(jìn)行操作回放就可以了。
是不是很簡(jiǎn)單?
問(wèn)題又來(lái)了。再看一眼我們的更新語(yǔ)句。
update t_user_innodb set name ='chanmufeng1994' where id = 1;
假如這條更新語(yǔ)句已經(jīng)被寫(xiě)入到了redo日志,還沒(méi)來(lái)得及寫(xiě)binlog的時(shí)候,MySQL宕機(jī)重啟了,我們看一下會(huì)發(fā)生什么。
因?yàn)閞edo日志可以在重啟的時(shí)候用于恢復(fù)數(shù)據(jù),所以寫(xiě)入磁盤(pán)的是chanmufeng1994。但是binlog里面沒(méi)有記錄這個(gè)邏輯日志,所以這時(shí)候用binlog去恢復(fù)數(shù)據(jù)或者同步到從庫(kù),就會(huì)出現(xiàn)數(shù)據(jù)不一致的情況。
所以在寫(xiě)兩個(gè)日志的情況下,就類(lèi)似于「分布式事務(wù)」的情況,如果你不清楚分布式事務(wù)是個(gè)什么東西也沒(méi)關(guān)系,我在之后的文章會(huì)介紹到。能夠明確的就是redo日志和binlog日志如果單純依次進(jìn)行提交是無(wú)法保證兩種日志都寫(xiě)成功或者都寫(xiě)失敗的。
我們需要「兩階段提交」。
6.3 兩階段提交
兩階段提交不是MySQL的專(zhuān)利,兩階段提交是一種跨系統(tǒng)維持?jǐn)?shù)據(jù)邏輯一致性的常見(jiàn)方案,尤其在分布式事務(wù)上,所以請(qǐng)讀者重點(diǎn)體會(huì)思想
我們把redo日志的提交分成兩步,兩步中redo日志的狀態(tài)分別是prepare和commit。步驟如下
- InnoDB存儲(chǔ)引擎將更改更新到內(nèi)存中后,同時(shí)將這個(gè)更新操作記錄到redo日志里面,此時(shí)redo日志處于
prepare狀態(tài); - 執(zhí)行器生成這個(gè)操作的binlog,并將binlog刷盤(pán);
- 執(zhí)行器調(diào)用InnoDB的提交事務(wù)接口,InnoDB把剛剛寫(xiě)入的redo日志改成
commit狀態(tài)。至此,所有操作完成。

加上兩階段提交之后我們?cè)賮?lái)看一下SQL更新語(yǔ)句的執(zhí)行流程。
7. SQL更新語(yǔ)句的執(zhí)行總結(jié)——終版

- 客戶(hù)端發(fā)送更新命令到MySQL服務(wù)器,經(jīng)過(guò)處理連接、解析優(yōu)化等步驟;
- Server層向InnoDB存儲(chǔ)引擎要id=1的這條記錄;
- 存儲(chǔ)引擎先從緩存中查找這條記錄,有的話(huà)直接返回,沒(méi)有則從磁盤(pán)加載到緩存中然后返回;
- Server層執(zhí)行器修改這條記錄的name字段值;
- 存儲(chǔ)引擎更新修改到內(nèi)存中;
- 存儲(chǔ)引擎記錄redo日志,并將狀態(tài)設(shè)置為
prepare狀態(tài); - 存儲(chǔ)引擎通知執(zhí)行器,修改完畢,可以進(jìn)行事務(wù)提交;
- Server先寫(xiě)了個(gè)binlog;
- Server提交事務(wù);
- 存儲(chǔ)引擎將redo日志中和當(dāng)前事務(wù)相關(guān)的記錄狀態(tài)設(shè)置為
commit狀態(tài)。
發(fā)布評(píng)論請(qǐng)先 登錄
為什么要?jiǎng)討B(tài)sql語(yǔ)句?
數(shù)據(jù)庫(kù)SQL語(yǔ)句電子教程
sql語(yǔ)句實(shí)例講解
MySQL存儲(chǔ)引擎完成更新語(yǔ)句執(zhí)行的方法
select語(yǔ)句和update語(yǔ)句分別是怎么執(zhí)行的
SQL后悔藥,SQL性能優(yōu)化和SQL規(guī)范優(yōu)雅
一條SQL語(yǔ)句是怎么被執(zhí)行的
簡(jiǎn)述SQL更新語(yǔ)句的執(zhí)行流程1
一條SQL更新語(yǔ)句的執(zhí)行流程1
一條SQL更新語(yǔ)句的執(zhí)行流程2

簡(jiǎn)述SQL更新語(yǔ)句的執(zhí)行流程2
評(píng)論