MySQL闪回需满足:binlog开启(log_bin=ON)、格式为ROW、binlog_row_image=FULL;精确定位DELETE_ROWS_EVENT起止偏移;用mysqlbinlog加--base64-output=DECODE-ROWS -v解析生成INSERT语句;恢复时需停复制、绕过GTID与外键约束。

确认 binlog 是否开启且格式为 ROW
MySQL 闪回依赖 binlog 记录每行数据变更,但默认可能关闭,或设为 STATEMENT 格式——这种格式不记录具体行变化,无法还原 DELETE。必须先验证:
- 执行
SHOW VARIABLES LIKE 'log_bin';,返回ON才有日志可查 - 执行
SHOW VARIABLES LIKE 'binlog_format';,值必须是ROW,MIXED在某些情况下也不可靠 - 检查
my.cnf中是否有binlog_row_image = FULL(5.6.2+ 默认开启,但低版本或手动调过可能为MINIMAL,会导致闪回缺失旧值)
定位误删语句对应的 binlog 位置
不能靠时间粗略估算,DELETE 操作在 binlog 中表现为 DELETE_ROWS_EVENT,需精确定位起止偏移。常用方法是用 mysqlbinlog 解析并过滤:
- 先查误删大致时间:
SELECT NOW();或从应用日志确认,再用mysqlbinlog --base64-output=DECODE-ROWS -v --start-datetime="2024-04-01 10:00:00" /var/lib/mysql/mysql-bin.000001查看 - 重点找含
### DELETE FROM `db`.`table`和### @1=...的块(这是 ROW 格式记录的旧值),记下# at 12345开始位置和下一个事件的# at 67890 - 如果误删跨多个 binlog 文件,得依次检查,注意
mysqlbinlog不支持自动拼接,需人工衔接
用 mysqlbinlog 反向生成 INSERT 语句
ROW 格式 binlog 里存的是被删行的“快照”,但 mysqlbinlog 默认输出的是反向操作(即把 DELETE 转成 INSERT),前提是参数用对:
- 必须加
--base64-output=DECODE-ROWS -v,否则看到的是乱码或空内容 - 用
--start-position=12345 --stop-position=67890精确截取,避免混入其他操作 - 输出重定向到文件后,会得到类似
INSERT INTO `db`.`table` VALUES (1,'abc',...);的语句——但注意:这些语句默认不含SET FOREIGN_KEY_CHECKS=0;,外键约束会报错 - 若表有自增主键,INSERT 可能因重复 ID 失败,需提前
SET SQL_LOG_BIN=0;或临时改auto_increment_offset
恢复时绕过主从延迟与 GTID 冲突
直接执行闪回 SQL 很可能在从库重放时报错,尤其是启用了 GTID 的集群:
- 在从库执行前,先
STOP SLAVE;,否则 binlog 事件会被再次复制,造成二次删除或主键冲突 - 如果用 GTID,闪回 SQL 会生成新事务号,可能触发
GTID_PURGED冲突;稳妥做法是:在目标实例上临时SET SESSION GTID_NEXT='AUTOMATIC';,或干脆在从库停复制后,用mysql --disable-log-bin连接执行 - 生产环境切忌在主库直接跑闪回脚本——哪怕只恢复一行,也建议先导出为临时表,核对数据后再
REPLACE INTO或INSERT ... ON DUPLICATE KEY UPDATE
真正难的不是解析 binlog,而是确认那几行数据在删除前到底长什么样;binlog_row_image=MINIMAL、未开启 log_slave_updates、或误删发生在 purged 日志之后,都会让闪回彻底失效。


















