生產環境誤執行 UPDATE student SET score='failure' 無 WHERE 條件,導致全表 8 行數據被覆蓋。傳統全備+增量 Binlog 重放耗時耗力,本文演示基於 binlog_format=ROW 的精準行級恢復全流程,僅需提取誤操作事務的 BEFORE IMAGE 即可秒級還原。
mysql> UPDATE student SET score='failure';
Query OK, 8 rows affected
-- 全表 score 欄位被覆蓋為 'failure'
binlog_format=ROW(記錄行變更前後圖像)GRANT ALL ON db.* TO 'admin_ro'@'%' IDENTIFIED BY 'pwd'; 避免恢復期間新寫入SET GLOBAL read_only=1; 切斷業務寫入mysqlbinlog --no-defaults -vv --base64-output=DECODE-ROWS mysql-bin.000001 \
| grep -B 15 'failure' | more
關鍵標識:Table_map 確認表 ID,Update_rows 事件包含 WHERE(舊值)與 SET(新值)。
mysqlbinlog --no-defaults -vv --base64-output=DECODE-ROWS mysql-bin.000001 \
| sed -n '/# at 249/,/COMMIT/p' > /opt/1.txt
# 核心 sed 腳本:交換 WHERE 與 SET 位置,提取舊值,替換 @1/@2... 為真實列名
sed '/WHERE/{:a;N;/SET/!ba;s/\([^\n]*\)\n\(.*\)\n\(.*\)/\3\n\2\n\1/}' 1.txt \
| sed -r '/WHERE/{:a;N;/@4/!ba;s/### @2.*//g}' \
| sed 's/### //g;s/\/\*.*/,/g' \
| sed '/WHERE/{:a;N;/@1/!ba;s/,/;/g};s/#.*//g;s/COMMIT,//g' \
| sed '/^$/d' > ./recover.sql
# 替換佔位符為真實列名
sed -i "s/@1/id/g;s/@2/name/g;s/@3/class/g;s/@4/score/g" recover.sql
sed -i -r 's/(score=.*),/\1/g' recover.sql
mysql> SOURCE /opt/recover.sql;
Query OK, 1 row affected (x8)
mysql> SELECT * FROM student;
+----+------+-------+-------+
| id | name | class | score |
+----+------+-------+-------+
| 1 | a | 1 | 56 |
| 2 | b | 1 | 61 |
| ... |
| 8 | h | 4 | 90 |
+----+------+-------+-------+
ROW 模式 Binlog 記錄:UPDATE ... WHERE (old_values) SET (new_values)
恢復邏輯:UPDATE ... SET (old_values) WHERE (pk=old_pk)
binlog_format=ROW,STATEMENT 模式無法提取行舊值來源:51CTO 技術博客