Mysql 如何使用 binlog 日志回滚操作失误的数据

一、背景

在日常开发运维中,我们可能会出现一些操作失误的情况,比如使用了错误的 sql 语句对 mysql 数据进行了 update、delete 等操作,失误操作导致数据出现问题,又或者架构设计上没有使用软删除机制,用户误删除了数据需要恢复。

那么如果出现这种情况,应该如何恢复失误/mysql 误删数据时,本文将使用几种常用方法一步一步带你回滚误删/误操的数据

二、准备测试数据

1. 创建测试表

sql 复制代码
create table jxy_pms.test_model
(
    create_time       bigint unsigned default 0     null,
    update_time       bigint unsigned default 0     null,
    delete_time       bigint unsigned default 0     null,
    test_model_id     varchar(255)                  not null
        primary key,
    name              varchar(255)                  null,
    remark            varchar(255)                  null
)
    collate = utf8mb4_unicode_ci;

2. 创建测试数据

sql 复制代码
insert into test_model (test_model_id, name, remark)
values ('1','test1','test-1'),
       ('2','test2','test-2'),
       ('3','test3','test-3');

select * from test_model

test_model_id  name   remark
1                 test1    test-1
2              test2    test-2
3                 test3    test-3

三、模拟误操作

sql 复制代码
delete from test_model

四、数据回滚

(一)方案一:云数据库恢复

如果你的 mysql 使用的时云数据库,比如阿里云、腾讯云,那么你可以到云数据库的控制台操作面板进行一键数据回滚,一般都可以选择对应的恢复区间,具体可以咨询对应的云数据库提供商,一般都会提供技术支持

优点:

  • 低风险
  • 操作简单
  • 有云供应商提供技术支持

缺点:

  • 恢复精度较低,没办法恢复指定的数据
  • 有可能恢复不全,云数据库是定期备份,可能还没来得及备份就被删了

(二)方案二:手动恢复

通过解读 binlog 日志内容,进行解析然后回放数据

binlog 日志:大白话:记录数据库的每个修改操作 sql

所以我们只需要找到对应的 binlog 日志中我们误操作的 sql 数据,然后编写对应的回放sql,就可以回滚数据

实操如下:

1. 查询 binlog 日志

sql 复制代码
show binary logs;  或  SHOW MASTER STATUS;

mysql-bin.000014    80019706    No
mysql-bin.000015    1326884    No
mysql-bin.000016    3650781    No
mysql-bin.000017    81424072    No
mysql-bin.000018    46681992    No
mysql-bin.000019    1075    No
mysql-bin.000020    207322979    No

可以看到最新的日志为:mysql-bin.000020

2. 找到删除语句,手动还原为插入语句

sql 复制代码
mysqlbinlog --no-defaults --verbose --base64-output=DECODE-ROWS --start-datetime='2025-01-16 15:12:00' --stop-datetime='2025-01-16 15:15:00' /var/lib/mysql/mysql-bin.000027 > /home/DataVolume/rec.sql
  • --base64-output=DECODE-ROWS 生成不加密的 sql 文件
  • --start-datetime 、stop-datetime 数据操作的时间区间

从 rec.sql 中找到对应的表 test_model 的删除操作,如果找不到,调整下--start-datetime 和 stop-datetime

找到删除的 sql 语句如下:

sql 复制代码
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
........
/*!*/;
# at 207319108
#240919 10:58:30 server id 1  end_log_pos 207319202 CRC32 0xe7b80345     Table_map: `jxy_pms`.`asynccron_cron_task` mapped to number 306

#240919 10:59:04 server id 1  end_log_pos 207321626 CRC32 0x6b3323a9     Table_map: `jxy_pms`.`test_model` mapped to number 315
# at 207321626
#240919 10:59:04 server id 1  end_log_pos 207321718 CRC32 0xb004dad7     Delete_rows: table id 315 flags: STMT_END_F
### DELETE FROM `jxy_pms`.`test_model`
### WHERE
###   @1='1'
###   @2='test1'
###   @3='test-1'
### DELETE FROM `jxy_pms`.`test_model`
### WHERE
###   @1='2'
###   @2='test2'
###   @3='test-2'
### DELETE FROM `jxy_pms`.`test_model`
### WHERE
###   @1='3'
###   @2='test3'
###   @3='test-3'
# at 207321718
#240919 10:59:04 server id 1  end_log_pos 207321749 CRC32 0x90b858f7     Xid = 7486642
COMMIT/*!*/;

然后写个脚本,解析这块 sql,重新翻译为 insert 语句即可

优点:

  • 适合一些少量数据的还原
  • 能准确还原指定的数据,操作简单
  • 重新执行的 sql,不会对已有的数据造成其他损坏

缺点:

  • 不适合一些大量数据的还原
  • 比较复杂,需要解读 binlog 日志,并且需要编写脚本

(三)方案三: 导入还原的 sql(未测试,慎用)

如果你的数据库不是用的云数据库,没有一键恢复功能,然后你又不想用方案二,觉得太复杂,你可以直接将 binlog 日志直接全部还原

  • 先导出 binlog 日志

    shell 复制代码
    mysqlbinlog --no-defaults --verbose --base64-output=DECODE-ROWS --start-datetime='2025-01-16 15:12:00' --stop-datetime='2025-01-16 15:15:00' /var/lib/mysql/mysql-bin.000027 > /home/DataVolume/rec.sql

    这里会导出 rec.sql 文件

  • 导入 sql

    shell 复制代码
    mysql -u root -p test < rec.sql

优点

  • 相比较方案二简单一些
  • 适合范围恢复

缺点

  • 恢复精度较低,比如你可能只需要恢复 2025-01-16 15:12:00 这个点的某条错误sql,但是这个点可能还有其他操作sql也会被一起恢复,
  • 恢复期间的操作数据可能存在丢失

⚠️⚠️⚠️:本方案没有实际验证过,请自行测试

总结

如果你用的是云数据库,并且恢复的数据量比较大,推荐【方案一】使用云数据库提供的恢复功能(非常适用那么删库跑路的恢复,哈哈哈哈)

如果你只是想要恢复某个个点、某些错误sql,那么可以使用【方案二】

原文地址

Mysql 如何使用 binlog 日志回滚操作失误的数据

相关推荐
Runing_WoNiu4 小时前
最佳左前缀法则(Optimal Left-Prefix Rule)
数据库·mysql
百里晴鸢5 小时前
mysql之主从复制
mysql
五月茶10 小时前
MySQL——黑马
数据库·mysql
一号IT男11 小时前
MySql MVCC的原理总结
数据库·mysql
荔枝吻11 小时前
【沉浸式解决问题】mysql-connector-python连接数据库:RuntimeError: Failed raising error.
数据库·python·mysql
一号IT男12 小时前
MySQL聚簇索引与非聚簇索引详解
数据库·mysql
苹果醋312 小时前
react_05create-react-app脚手架详细解析(export)
java·运维·spring boot·mysql·nginx
就叫飞六吧12 小时前
mysql全屏终端全量、部分备份、恢复脚本
android·mysql·adb
fenglllle1 天前
项目中MySQL遇到的索引失效的问题
数据库·mysql