mysql误删数据快速恢复

MySQL数据恢复技巧
本文详细介绍如何使用MySQL的binlog功能进行数据恢复,包括binlog的三种格式及其配置,以及使用binlog2sql和mysqlbinlog工具的具体步骤。适用于后端研发人员在遇到产品需求临时修改线上数据时,不慎误删或修改数据后的快速恢复。

原文:https://www.jianshu.com/p/c9a2fe3f4534

相信后端研发的同学在开发过程经常会遇到产品临时修改线上数据的需求,如果手法很稳那么很庆幸可以很快完成任务,很不幸某一天突然手一抖把表里的数据修改错误或者误删了,这个时候你会发现各种问题反馈接踵而来。如果身边有BDA或者有这方面经验的同事那么可以很快解决这个问题,如果没有那么希望这篇文章可以帮到你。

binglog介绍

首先第一步保证mysql已经开启binlog,查看命令:

show variables like '%log_bin%'

mysql binlog分三种格式 :

Statement : 会在binlog中记录每一条执行修改数据的sql语句的相关信息,优点是不需要记录每一行的变化,减少了binlog日志量,节约了IO
Row : 会在binlog中记录每一修改语句的详细信息,包括数据在修改之前和修改之后的数据的具体信息,好处是会清晰记录每一条修改的详细信息,不好的地方是会产生大量日志
Mixed :这种格式实际上就是Statement和Row的结合体,如果遇到表结构变更就会以Statement来记录,如果涉及语句修改那么就以Row格式记录

这里的binlog格式推荐row,my.cnf 的配置可参考 :

server_id = 1001
log_bin = /var/log/mysql/mysql-bin.log
max_binlog_size = 1G
binlog_format = row
binlog_row_image = full

我们来模拟一些数据:

CREATE TABLE `user` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(125) NOT NULL DEFAULT '' COMMENT '名称',
  `age` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '年龄',
  `sex` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '性别',
  `deleted` tinyint(4) unsigned DEFAULT '0',
  `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表测试';
INSERT INTO `user` (`id`, `name`, `age`, `sex`, `deleted`, `created`)
VALUES
    (1, '小王', 21, 1),
    (2, '小张', 22, 1),
    (3, '小红', 22, 0),
    (4, '小楠', 23, 0),
    (5, '小柱', 25, 1);

然后我们把数据全部删掉

delete from `user`

数据恢复方法一 :

使用开源框架binlog2sql : https://github.com/danfengcao/binlog2sql
好处是成熟,稳定,上手难度比较低且可直接生成可执行sql,示例 :

python /binlog2sql/binlog2sql.py --flashback -h127.0.0.1 -P3306 -uroot -p'123456' -dlocal -tuser --start-file='mysql-bin.000038' --sql-type=DELETE --start-datetime='2017-12-17 19:39:33' --stop-datetime='2017-12-17 19:40:01' >/**/data6.sql

解析后的结果大概是这样

INSERT INTO `local`.`user`(`name`, `created`, `deleted`, `age`, `sex`, `id`) VALUES ('小柱', '2017-12-18 13:21:52', 0, 25, 1, 5); #start 1890 end 2244 time 2017-12-19 09:20:26
INSERT INTO `local`.`user`(`name`, `created`, `deleted`, `age`, `sex`, `id`) VALUES ('小楠', '2017-12-18 13:21:52', 0, 23, 0, 4); #start 1890 end 2244 time 2017-12-19 09:20:26
INSERT INTO `local`.`user`(`name`, `created`, `deleted`, `age`, `sex`, `id`) VALUES ('小红', '2017-12-18 13:21:52', 0, 22, 0, 3); #start 1890 end 2244 time 2017-12-19 09:20:26
INSERT INTO `local`.`user`(`name`, `created`, `deleted`, `age`, `sex`, `id`) VALUES ('小张', '2017-12-18 13:21:52', 0, 28, 1, 2); #start 1890 end 2244 time 2017-12-19 09:20:26
INSERT INTO `local`.`user`(`name`, `created`, `deleted`, `age`, `sex`, `id`) VALUES ('小王', '2017-12-18 13:21:52', 0, 21, 1, 1); #start 1890 end 2244 time 2017-12-19 09:20:26

参数--sql-type建议加上,因为可能会有其他类型语句生成干扰了执行结果
如果是线上阿里云或者其他产品建议先去管理后台找到事发时间的binlog日志下载下来,先在测试环境验证数据回滚结果.

数据恢复方法二:

当线上数据出现错误的时候首先可以询问具体操作人记录时间点,这个时候可以借助mysql自带的binlog解析工具mysqlbinlog,具体位置在mysql安装目录**/mysql/bin/下,示例:

mysqlbinlog --base64-output=decode-rows -v --start-datetime="2017-12-15 17:48:49" --stop-datetime="2017-12-16 23:59:49" /usr/local/mysql/mysql-bin.000038 >/**/data.sql

如果是阿里云rds或者其他产品可通过远程方式解析

mysqlbinlog --no-defaults -u账号 -p密码 -h ***.rds.aliyuncs.com --read-from-remote-server mysql-bin.000180 --base64-output=decode-rows -v > /data.sql

这里因为binlog文件默认是通过base64编码过的,所以需要加上--base64-output=decode-rows -v
解析后的格式大概是这样的 :

### DELETE FROM `local`.`user`
### WHERE
###   @1=1
###   @2='小王'
###   @3=21
###   @4=1
###   @5=0
###   @6='2017-12-18 13:21:52'
### DELETE FROM `local`.`user`
### WHERE
###   @1=2
###   @2='小张'
###   @3=28
###   @4=1
###   @5=0
###   @6='2017-12-18 13:21:52'
....

仔细查看这种格式文件,发现这种格式文件并不能直接执行,但是在where条件后面记录了被删除之前的原始数据,需要借助sed、awk把SQL文本转换成真正的SQL。或者当你在遇到开源框架解决不了的情况下,可以根据具体场景尝试手动把这种格式的文件解析成可执行的sql语句。



作者:qtshe
链接:https://www.jianshu.com/p/c9a2fe3f4534
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

<think>嗯,用户想恢复误删MySQL数据,这确实是个紧急情况。用户可能正在焦虑中,需要快速可靠的解决方案。 根据数据恢复经验,MySQL数据恢复主要分三种情况:有备份、无备份但binlog开启、以及最糟糕的无任何准备。用户没有说明环境,所以需要覆盖所有可能性。 首先考虑最理想情况——有备份。这是最简单的恢复方式,直接还原备份文件即可。需要提醒用户注意备份的新旧程度,避免恢复后丢失最新数据。 如果用户没有备份但开启了binlog,就有很大希望。需要指导用户立即停止写入操作,防止日志被覆盖。然后通过mysqlbinlog工具提取删除前的日志,生成恢复SQL。这里要强调position或时间点定位的技巧。 最麻烦的是既无备份又没开binlog的情况。这时候只能尝试第三方工具了。比如Linux下的extundelete或者商业工具,但成功率无法保证。需要提醒用户立即停止服务,避免磁盘覆盖。 用户可能是DBA也可能是开发者,所以操作步骤要写详细些。特别是使用binlog恢复那段,需要给出具体命令示例,包括查看日志列、导出SQL等关键操作。时间点定位那里要特别说明如何精确到秒。 最后一定要强调预防措施。这次恢复后建议用户立即设置定期备份和binlog,可以用mysqldump配合cron实现自动化。毕竟恢复数据永远是下策,预防才是关键。 相关问题设计要覆盖延伸需求:binlog配置验证、备份脚本编写、不同存储引擎的恢复差异等。用户解决当前问题后很可能需要这些进阶知识。</think>以下是MySQL数据误删除的恢复方法,按优先级排序: ### 一、有备份时的恢复(推荐方案) ```sql -- 停止MySQL服务 sudo systemctl stop mysql -- 还原完整备份(示例) mysql -u root -p dbname < backup_full.sql -- 还原增量binlog(关键步骤) mysqlbinlog --start-datetime="2024-06-25 09:00:00" \ --stop-datetime="2024-06-25 10:30:00" mysql-bin.000001 | mysql -u root -p ``` > **注意**:时间范围需覆盖删除操作前的有效数据 ### 二、无备份但开启binlog 1. **紧急处理** ```bash # 立即锁定防止写入 FLUSH TABLES WITH READ LOCK; # 复制binlog文件备份 cp /var/lib/mysql/mysql-bin.* /safe_path/ ``` 2. **解析binlog恢复** ```bash # 定位删除事件位置 mysqlbinlog --base64-output=decode-rows -v mysql-bin.000002 | grep -A 10 "DELETE" # 生成恢复SQL(反向转换DELETE为INSERT) mysqlbinlog --start-position=12345 --stop-position=56789 \ mysql-bin.000002 | sed -n "s/^### DELETE FROM/### INSERT INTO/p; s/^### WHERE/### SELECT/p;" | awk '{print $0";"}' > recovery.sql ``` ### 三、无任何准备的恢复 1. **物理恢复工具(需立即停止MySQL)** - InnoDB引擎:使用`Percona Data Recovery Tool` ```bash perl ibd_recovery -f /var/lib/mysql/dbname/tablename.ibd ``` - MyISAM引擎:尝试`myisamchk --safe-recover` 2. **磁盘扫描工具(极端情况)** ```bash # Linux环境示例 photorec /dev/sda1 # 扫描文件碎片 ``` --- ### 预防措施(恢复后必做) 1. **启用自动备份** ```bash # 每日全量备份脚本 mysqldump -u root -p --all-databases | gzip > /backups/full_$(date +%F).sql.gz ``` 2. **配置binlog** ```ini # my.cnf配置 [mysqld] server-id=1 log-bin=mysql-bin expire_logs_days=7 # 保留7天日志 ``` 3. **事务保护机制** ```sql -- 重要操作前启用安全模式 SET autocommit=0; START TRANSACTION; -- 业务操作 -- COMMIT; ``` > **关键提示**:删除后第一时间停止数据库写入,数据覆盖是最大风险源[^1]。若使用云数据库(如RDS),立即联系厂商获取快照恢复支持。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值