以前有過一篇關于MySQL查詢語句的執行過程,這里總結一下update語句的執行過程。由于update涉及到數據的修改,所以,很容易推斷,update語句比select語句會更復雜一些。

1,準備
創建一張test表
CREATE TABLE `test` ( `id` int(11) NOT NULL AUTO_INCREMENT, `c` int(11) NOT NULL DEFAULT '0' COMMENT '數值', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='測試表';
插入三條數據
INSERT INTO `test` (`c`) VALUES (1), (2), (3);
2,測試
加入我要把第一條數據的 c 值 加 1,則
UPDATE `test` SET `c` = `c` + 1 WHERE `id` = 1;
按照我們平常的思路,就是找出這條記錄,把它的值改好,保存就OK了。
但我們追究一下細節,由于涉及到修改數據,所以涉及到日志了。
3 操作順序
3.1 查找記錄:執行器先找引擎取id=1這一行。ID是主鍵,引擎直接用樹搜索找到這一行。如果id=1這一行所在的數據頁本來就在內存中,就直接返回給執行器;否則,需要先從磁盤讀入內存,然后再返回;
3.2 執行器拿到引擎返回的行數據,把num改為2,得到新的一行數據,再調用引擎接口寫入這行新數據;
3.3 引擎將這行新數據更新到內存中,同時將這個更新操作記錄到redo log里面,此時redo log處于prepare狀態;
3.4 引擎告知執行器,我執行完成了,你隨時可以調我的接口提交事務了;
3.5 執行器生成這個操作的binlog,并把binlog寫入磁盤。
3.6 執行器調用引擎的提交事務接口,引擎把剛剛寫入的redo log改成提交commit狀態,更新完成。

binlog是MySQL內部實現二階段提交的協調者,它為每個事務分配一個事務ID: XID
一階段:
開啟事務,redo log 和 undo log已經記錄了對應的日志,此時事務狀態為prepare
二階段:
binlog 完成write和fsync后,成功,事務一定提交了,否則事務回滾 發送commit,清除undo信息,刷redo,設置事務狀態為completed
4, 兩種日志 4.1 重做日志 redo log
redo log 通常是物理日志,記錄的是數據頁的物理修改,而不是某一行或某幾行修改成怎樣怎樣,它用來恢復提交后的物理數據頁(恢復數據頁,且只能恢復到最后一次提交的位置)。
一般更新會有如下做法:
直接查詢原始數據,立馬更新; 先找個臨時記事本,做下記錄,等不忙的時候/結算時候進行核算更新。
第一種做法在高并發IO的情況下非常的不容樂觀。所以一般都會采用第二種方式。
新聞熱點
疑難解答