【mysql】数据误删了? 关键时刻可以通过binlog挽救
tips: 删除数据之前一定要备份好 养成好的习惯 数据库定期备份数据 远比学会使用binlog恢复数据更重要,binlog是最后一道防线 且非常非常麻烦。
数据备份习惯:
1.delete数据前 备份insert语句(只要不是老项目 基本都有逻辑删除字段),update数据前 备份回滚的update语句
2. 批量改生产数据时,可以备份整个表的结构和数据 结构包括索引等
3. 定期备份:可以通过定时mysqldump备份 + 备份binlog文件的形式
有经验的同学可以评论区补充更多方便的方式。
文章目录
- binlog配置与查看
- 配置
- 查看
- mysqlbinlog命令
- 三方工具: canal2sql
binlog配置与查看
配置
my.inf
# 生产环境下 强烈建议配置一个值 不然binlog文件非常庞大 值的大小 需要根据业务数据量自行估算
max_binlog_size=100M
# binlog路径 注意下面是windows 测试环境
log-bin=D:\dev-software\mysql-8.0.32-winx64\log\log-bin
#数据库标志ID,唯一
server-id=1
#binlog-do-db可以被从服务器复制的库
binlog-do-db=test
#binlog-ignore-db不可以被从服务器复制的库
binlog-ignore-db=mysql
查看
在navicat 或者mysql终端中输入:
# 查看有哪些binlog文件
SHOW BINARY LOGS;
在生产环境 务必看清楚binlog size大小是多少 如果9位数以上 过于庞大 不建议执行该命令 卡崩了别找我; 只建议测试环境 本地环境学习时使用
# 查看具体的binlog文件 替换成 自己的文件名
SHOW BINLOG EVENTS IN 'log-bin.000263';
info中 包含 Begin即一个事务开始 commit即事务结束。
mysqlbinlog命令
(注意这是windows环境 路径是windows的)
D:\dev-software\mysql-8.0.32-winx64\bin> mysqlbinlog --base64-output=DECODE-ROWS -vv --start-datetime="2025-09-25 13:00:00" --stop-datetime="2025-09-25 17:30:00" "D:\\dev-software\\mysql-8.0.32-winx64\\log\\log-bin.000263" > recover.txt
参数解释:
–base64-output=DECODE-ROWS:把 row-based 的日志解码成可读 SQL。
-vv:显示更详细信息。--start-datetime:只解析某个时间之后的日志。--stop-datetime:只解析某个时间之前的日志。"log-bin.000263":具体的 binlog 文件名(替换成自己的)。> binlog.txt:输出到文件便于分析。
我们选取binlog.txt 的一部分 分析一下:
说明执行了一条删除操作,注意这个日志是不带列名的 ,
例如@1=1871388470542786563
表示第一列的值为1871388470542786563
如果我们要恢复这条数据 则需要手动将delete改写成insert语句 将列名拼接上去 如果只是误删了一条数据还好 但凡多几条 甚至成千上万条 手动改写是非常不现实的。
三方工具: canal2sql
人气比较高的是binlog2sql 但是很久没有维护了 mysql支持的版本停在了mysql5 pyhton写的一个项目 requirement的依赖也是很老了,测试mysql8环境失败。
博主在阿里的canal项目中看到了一个链接 提到了canal2sql
使用比较简单,按照readme命令输入即可
binlog文件模式命令
java -jar ./canal2sql-${version}.jar -mode file -file_url 'file:/Users/abc/binlog/mysql-bin.000474' -uroot -proot -P3306 -hlocalhost
# 离线模式 (即不用连接数据库 但需要传入ddl文件)
java -jar ./canal2sql-${version}.jar -mode file -ddl '/Users/xxx/ddl.sql' -file_url 'http://localhost:8080/binlog/mysql-bin.000474'
离线模式的ddl文件是创建表的语句 务必带上数据库名,例如:
CREATE TABLE `test`.`t_test_t` (`id` bigint NOT NULL AUTO_INCREMENT,`des` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,`mark` int NULL DEFAULT NULL,`version` int NULL DEFAULT NULL,`create_user` bigint NULL DEFAULT 0,PRIMARY KEY (`id`) USING BTREE,INDEX `idx_desc`(`des` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1871388470542786565 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic
canal2sql需要通过解析这个语句用来拼接字段名
(上文提过 binlog是不带字段信息的)
需要注意的是,windows环境下命令 需要格外注意路径:
windows文件 在线模式命令:
java -jar canal2sql-1.1.6-SNAPSHOT.jar -mode file -file_url file:///D:/dev-software/mysql-8.0.32-winx64/log/log-bin.000263 -uroot -proot -P3306 -h127.0.0.1 -A -B
-model file 表示binlog文件模式
-file_url 声明文件路径 用的java的URL类 所以支持file和http路径 ,windows路径注意不要加单引号 file:后面三个/ -A 追加模式,支持原SQL和回滚SQL同时显示
-B 在-A开启基础上 把回滚sql展示 原sql注释 (-A是把回滚sql给注释了)
目前已知离线模式下 可能有bug:
java -jar canal2sql-1.1.6-SNAPSHOT.jar -mode file -file_url file:///D:/dev-software/mysql-8.0.32-winx64/log/log-bin.000263 -ddl C://Users//10057//Desktop//t_test_t.sql -A -B -start_time "2025-09-26 14:30:00" -end_time "2025-09-26 15:30:00"
博主提的issue 在等待作者回复:
https://github.com/zhuchao941/canal2sql/issues/31
另外 项目是直接将sql打印的,我们自己使用时 需要改写一下Canal2SqlUtils.printSql方法的代码 输出到一个txt文件中 方便我们复制并执行回滚sql
执行结果示例: