实际工作中总会发生数据误删除的场景,在没有备份情况下,如何快速恢复误删数据就显得非常重要。

本文基于MySQL的binlog日志机制,当日志格式设置为“binlog_format=ROW”时,记录一步一步手动解析binlog、恢复误删数据的全过程,供大家参考使用。

一、确定删除时间段

查看数据库日志名字,查看操作事件,确认删除的具体时间,以定位删除的日志内容。

show master logs;

show binlog events in 'binlog.000067';

show binlog events in 'binlog.000067' FROM 1293303 LIMIT 0, 20;

通过类似如上的语句可确定具体的日志名字,具体的操作时间点或position

mysql> show binlog events in 'binlog.000002' FROM 2853160 LIMIT 0, 20;
+---------------+---------+----------------+-----------+-------------+--------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+---------------+---------+----------------+-----------+-------------+--------------------------------------+
| binlog.000002 | 2853160 | Query | 1 | 2853246 | BEGIN |
| binlog.000002 | 2853246 | Table_map | 1 | 2853315 | table_id: 94 (liking.wp_options) |
| binlog.000002 | 2853315 | Update_rows | 1 | 2859755 | table_id: 94 flags: STMT_END_F |
| binlog.000002 | 2859755 | Query | 1 | 2859842 | COMMIT |
| binlog.000002 | 2859842 | Anonymous_Gtid | 1 | 2859921 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| binlog.000002 | 2859921 | Query | 1 | 2860007 | BEGIN |
| binlog.000002 | 2860007 | Table_map | 1 | 2860076 | table_id: 94 (liking.wp_options) |
| binlog.000002 | 2860076 | Update_rows | 1 | 2866516 | table_id: 94 flags: STMT_END_F |
| binlog.000002 | 2866516 | Query | 1 | 2866603 | COMMIT |
| binlog.000002 | 2866603 | Anonymous_Gtid | 1 | 2866682 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| binlog.000002 | 2866682 | Query | 1 | 2866759 | BEGIN |
| binlog.000002 | 2866759 | Table_map | 1 | 2866828 | table_id: 94 (liking.wp_options) |
| binlog.000002 | 2866828 | Delete_rows | 1 | 2866936 | table_id: 94 flags: STMT_END_F |
| binlog.000002 | 2866936 | Query | 1 | 2867014 | COMMIT |
| binlog.000002 | 2867014 | Anonymous_Gtid | 1 | 2867093 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| binlog.000002 | 2867093 | Query | 1 | 2867179 | BEGIN |
| binlog.000002 | 2867179 | Table_map | 1 | 2867247 | table_id: 95 (liking.wp_postmeta) |
| binlog.000002 | 2867247 | Update_rows | 1 | 2867347 | table_id: 95 flags: STMT_END_F |
| binlog.000002 | 2867347 | Query | 1 | 2867434 | COMMIT |
| binlog.000002 | 2867434 | Anonymous_Gtid | 1 | 2867513 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
+---------------+---------+----------------+-----------+-------------+--------------------------------------+

二、取到指定时间段的所有sql语句

mysqlbinlog --no-defaults --base64-output=decode-rows -vv --start-datetime="2022-10-27 16:54:00" --stop-datetime="2022-10-27 18:27:00" binlog.000288 > liking.sql

三、取delete语句

sed -n '/### DELETE FROM 数据脱敏.数据脱敏数据脱敏/,/COMMIT/p' liking.sql > liking-1.sql

得到类似如下结果:

head -50 liking-1.sql
### DELETE FROM `数据脱敏`.`数据脱敏数据脱敏`
### WHERE
### @1=222248 /* INT meta=0 nullable=0 is_null=0 */
### @2='数据脱敏数据脱敏' /* VARSTRING(256) meta=256 nullable=1 is_null=0 */
[此处省略第3~45个记录行]
### @46='数据脱敏' /* VARSTRING(1020) meta=1020 nullable=1 is_null=0 */
### @47='订单' /* VARSTRING(1020) meta=1020 nullable=1 is_null=0 */
### @48='数据脱敏' /* VARSTRING(1020) meta=1020 nullable=1 is_null=0 */

四、只保留以###开始的行数据

sed -n '/^###/'p liking-1.sql > liking-2.sql

五、去掉开头的###字符

sed 's/### //g' liking-2.sql > liking-3.sql

得到类似如下结果:

head -50 liking-3.sql
DELETE FROM `数据脱敏`.`数据脱敏数据脱敏`
WHERE
@1=222248 /* INT meta=0 nullable=0 is_null=0 */
@2='数据脱敏数据脱敏' /* VARSTRING(256) meta=256 nullable=1 is_null=0 */
[此处省略第3个~第45个字段]
@46='数据脱敏' /* VARSTRING(1020) meta=1020 nullable=1 is_null=0 */
@47='订单' /* VARSTRING(1020) meta=1020 nullable=1 is_null=0 */
@48='数据脱敏' /* VARSTRING(1020) meta=1020 nullable=1 is_null=0 */

六、以#作分隔符将以/*开始的内容用,替换

sed 's#/*.*#,#g' liking-3.sql > liking-4.sql

得到如下结果:

head -50 liking-4.sql
DELETE FROM `数据脱敏`.`数据脱敏数据脱敏`
WHERE
@1=222248 ,
@2='数据脱敏数据脱敏' ,
[此处省略第3个~第45个字段]
@46='数据脱敏' ,
@47='订单' ,
@48='数据脱敏' ,

七、浏览结果做对应处理

鉴于还有一些insert、update语句,只取出前面的delete语句:

sed -n '1,493200p' liking-4.sql > liking-5.sql

八、全文替换关键字,将delete改成insert

将'DELETE FROM'改成'INSERT INTO'

将'WHERE'改成'SELECT'

sed 's#DELETE FROM#INSERT INTO#g' liking-5.sql > liking-6.sql

sed 's#WHERE#SELECT#g' liking-6.sql > liking-7.sql

得到如下结果:

head -50 liking-7.sql
INSERT INTO `数据脱敏`.`数据脱敏数据脱敏数据脱敏`
SELECT
@1=222248 ,
@2='数据脱敏数据脱敏' ,
[此处省略第3个~第45个字段]
@46='数据脱敏' ,
@47='订单' ,
@48='数据脱敏' ,

九、匹配'@48='开头以','结尾的行,把','替换成';'

sed -r 's#(@48=.)(,)#\1;#g' liking-7.sql > liking-8.sql

-r: 是指将正则表达式中的需要转义的字符设置成不需转义

括号用来匹配连续出现的内容

.
标识匹配除换行符\n外的任何单元符

为了把','去掉,单独(,)

\1是用来取()表示符的第一个,并在后面拼接上';'

本次恢复的记录都是48个字段,最后加分号,标识SQL结束,比较容易理解。

得到类似如下结果:

INSERT INTO `数据脱敏`.`数据脱敏数据脱敏数据脱敏`
SELECT
@1=222248 ,
@2='数据脱敏数据脱敏' ,
[此处省略第3个~第45个字段]
@46='数据脱敏' ,
@47='订单' ,
@48='数据脱敏' ;

十、把'@??='替换成'',也就是去掉类似'@11='字样部分

sed -r 's#(@.=)(.)#\2#g' liking-8.sql > liking-9.sql

得到类似如下结果:

head -50 liking-9.sql
INSERT INTO `数据脱敏`.`数据脱敏数据脱敏`
SELECT
222248 ,
'CMHE-202200393' ,
'数据脱敏数据脱敏数据脱敏数据脱敏数据脱敏数据脱敏数据脱敏数据脱敏数据脱敏数据脱敏数据脱敏数据脱敏数据脱敏数据脱敏' ,
4.1772e+07 ,
'\'8000062202216124' ,
[此处省略第6个~第45个字段]
'数据脱敏' ,
'订单' ,
'马蕾' ;

十一、最后拼接 commit 语句

sed -i '$a commit;' liking-9.sql

查看最后几行确认:

tail -51 liking-9.sql
INSERT INTO `数据脱敏`.`数据脱敏数据脱敏`
SELECT
251837 ,
'CMHE-202101003' ,
'数据脱敏数据脱敏数据脱敏数据脱敏数据脱敏' ,
5.04e+08 ,
'\'8000004202200006' ,
[此处省略第6个~第45个字段]
'数据脱敏' ,
'订单' ,
'陈鹏3' ;
commit;

十二、浏览、调整个别异常格式字段

此时需大概浏览得到的文本结果,尤其关注转义符,如有必要,需及时调整。

发现尚存在类似如下字段格式

''8000004202200006'

如需去掉'

则如下操作:

sed "s#\'##g" liking-9.sql > liking-10.sql

最后确认如下:

tail -51 liking-10.sql
INSERT INTO `数据脱敏`.`数据脱敏数据脱敏`
SELECT
251837 ,
'CMHE-202101003' ,
'数据脱敏数据脱敏数据脱敏数据脱敏数据脱敏' ,
5.04e+08 ,
'8000004202200006' ,
[此处省略第6个~第45个字段]
'数据脱敏' ,
'订单' ,
'陈鹏3' ;
commit;

十三、执行恢复数据

经过审视、调整后,此时得到的结果,已经可以正常执行INSERT操作恢复数据了!

写在最后,再次强调,备份是运维第一要务,备份的重要性再怎么强调也不为过,除非你可以承受数据丢失带来的后果。

数据千万行,备份最重要;数据不备份,丢失泪两行!

参考文档:

https://blog.csdn.net/qq_37701372/article/details/115188461

MySQL误删恢复方法2的更多相关文章

  1. 二.误删除MySQL用户,恢复方法

    误删除MySQL用户导致无法进入数据库 一.方法一 1.停止数据库 [root@db02 ~]# /etc/init.d/mysqld stop 2.跳过授权表,跳过网络启动数据库 [root@db0 ...

  2. oracle数据库误删恢复方法

    一.如果只是误删部分数据或者某条数据可以通过 1.select * from 误删除的表明 as of timestamp to_Date('恢复年月日  时分秒', '恢复时间格式')       ...

  3. windows系统下系统变量path误删恢复方法

    每台计算机安装程序不同,环境变量path会有不同,若误删了环境变量path,可以如下完美解决.   Win+R 输入regedit打开注册表(开始-运行里输入regedit) 找到  HKEY_LOC ...

  4. Mysql误删表中数据与误删表的恢复方法

    由于头两天面试时被问了这样一个问题,如果某同事误删了某个表,你该怎么恢复? 当时想了一下,因为博主没有遇到过这个问题,但是也多少了解一些,所以就回答通过mysql的binlog日志进行恢复. 面试官当 ...

  5. MySQL全备+binlog恢复方法之伪装master【原创】

    利用mysql全备 +binlog server恢复方法之伪装master 单实例试验 一.试验环境 10.72.7.40 实例 mysql3306为要恢复的对象,mysql3306的全备+binlo ...

  6. MySQL密码的恢复方法

    MySQL密码的恢复方法之一 1.首先确认服务器出于安全的状态,也就是没有人能够任意地连接MySQL数据库. 因为在重新设置MySQL的root密码的期间,MySQL数据库完全出于没有密码保护的 状态 ...

  7. mysql导出csv/sql/newTable/txt的方法,mysql的导入txt/sql方法...mysql备份恢复mysqlhotcopy、二进制日志binlog、直接备份文件、备份策略、灾难恢复.....................................................

    mysql备份表结构和数据 方法一. Create table new_table_nam备份到新表:MYSQL不支持: Select * Into new_table_name from old_t ...

  8. IIS误删了默认网站,恢复方法

    有时候安装好IIS后,会不小心把IIS的默认网站删除.重新去新建可能会出现一些错误例如"提示文件已存在无法执行"等奇怪的错误,下面是具体的默认网站的恢复方法 找到目录C:\wind ...

  9. MySQL 误删数据、误更新数据(update,delete忘加where条件)

    MySQL 误操作后数据恢复(update,delete忘加where条件) 关键词:mysql误删数据,mysql误更新数据 转自:https://www.cnblogs.com/gomysql/p ...

  10. 6种innodb数据字典恢复方法

    6种innodb数据字典恢复方法 https://dev.mysql.com/doc/refman/5.7/en/innodb-troubleshooting-datadict.html frm文件重 ...

随机推荐

  1. DevOps|中式土味OKR与绩效考核落地与实践

    昨天一个小伙伴和我讨论了一下OKR和绩效管理,所以这次想简单明了地说下在中国怎么做比较合适,很多高大上的理论无法落地也是空中楼阁. 首先说一些,我个人的理解 道德品质和能力素质决定了一个人的职位行为 ...

  2. AWVS——自动化检测发现漏洞

    AWVS简介 *AWVS作为一个工具,不可能把所有漏洞扫描出来,仅仅是作为一个渗透网站时的辅助工具 自动化Web漏洞扫描工具(基于漏洞匹配方法,通过网络爬虫测试网站安全) AWVS通过SQL注入攻击. ...

  3. 查看C语言程序对应的汇编代码

    在终端输入 gcc -S main.c 命令的意思是 编译不汇编 mian.c 可以换成想要汇编的C语言程序 然后生成 main.s 使用文本编辑器查看即可

  4. requests高级用法、代理池搭建

    requests高级用法 1.自动携带cookie的session对象 # session对象---->已经模拟登录上了一些网站--->单独把cookie 取出来 import reque ...

  5. 关于 Task 简单梳理

    〇.前言 Task 是微软在 .Net 4.0 时代推出来的,也是微软极力推荐的一种多线程的处理方式. 在 Task 之前有一个高效多线程操作累 ThreadPool,虽然线程池相对于 Thread, ...

  6. 为什么 PostgreSQL 的适用性很强?

    说起使用数量最大的数据库SQLite 它是全球最广泛部署的数据库引擎.它存在于你的手机中,存在于你的浏览器中,如果你搜索你的电脑,你也会在其中找到它的 .db 文件.SQLite 受到 Postgre ...

  7. Codeforces Round #888 (Div. 3) A-G

    比赛链接 A 代码 #include <bits/stdc++.h> using namespace std; using ll = long long; bool solve() { i ...

  8. 避坑 | OI排雷新生态

    可持久化线段树 query 的时候两结点的 sz 相减的时候一定是左儿子相减. 可持久化线段树建新点要将原来的不更改的节点连接上. 动态规划也可以倒着考虑. P3957的单调队列是先加入后删除,否则加 ...

  9. [golang]获取本机IP

    前言 方便在内网环境中获取服务器本机IP,省了在脚本中过滤ip或ifconfig的结果. 如果内网中有nginx的话,通过nginx获取本机IP也很方便,可参考 借助nginx自动获取本机IP 示例代 ...

  10. sqli-labs全通关payload

    less-1: less-2: less-3: less-4: less-5: less-6: less-7: outfile,dumpfile,load_file函数的用法如下所示: less-8: ...