在生产库执行update时只添加了STATUS(状态)条件,将所有状态为‘E’的数据全部改为了‘D’
思路:
操作步骤主要参考自文章:https://blog.csdn.net/weixin_43733154/article/details/104675222
结合原作者文章及实际情况,整理解决思路主要概况为:
1、使用show master status 命令查看当前binlog文件;
2、使用mysqlbinlog命令通过误操作时间及误操作表的条件,导出误操作记录文件;
3、查看导出的误操作记录文件,保留误操作sql语句;
4、处理导出的误操作语句文件,反向更新误操作的记录。
处理:
实际操作过程中遇到部分问题,与解决思路有部分偏差。实操过程记录:
在Navicat中执行show master status 命令,得到当前binlog文件为:mysql-bin.000006,position居然到了8亿多,说明很久没有替换新的binlog文件了;
顺便使用flush logs 命令生成新的binlog文件;
SSH连接数据库服务器,进入mysql的bin目录下
使用mysqlbinlog命令加入误操作时间和库名条件,导出对应.sql文件,命令如下:
./mysqlbinlog --start-datetime='2021-02-25 17:00:00' --database=[dbName] mysql-bin.000006 >a.sql
找到对应表名的操作记录,如下图:
图中可以找到误操作的节点为:891012321 - 892709040,日志二进制是因为起初执行mysqlbinlog命令时没有加 --base64-output=decode-rows -vv ,未对文件解码,如果一开始就解码,应该可以省略再取一次文件的步骤;
执行命令./mysqlbinlog --base64-output=decode-rows -vv --start-position=891012321 --stop-position=892709040 mysql-bin.000006 >a1.sql获取到精确的误操作明文记录;
编辑文件,将语句调整为反向更新语句:
执行命令 sed -n '/^###/'p a1.sql >b.sql 【将第一个###前面的内容删除】
执行命令 sed 's/### //g' b.sql >c.sql 【将每行前面的###删除】
执行命令 sed '/WHERE/{:a;N;/SET/!ba;s#WHERE#set#g}' c.sql >d.sql
执行命令 sed '/SET/{:a;N;/\n/!ba;s#SET#where#g}' d.sql >e.sql 【这两句将原来的WHERE改成SET,SET改成WHERE】
结合实际表结构,将@1这种字段名改为表中的字段名,由于这次误操作是将表中的STATUS字段从‘E’改为了‘D’,所以仅需要将SET中的STATUS和WHERE中的ID改回到表字段名即可:
执行命令 sed '/set/{:a;N;/where/!ba;s#@11=#STATUS=#g}' e.sql >f.sql
执行命令 sed '/where/{:a;N;/\n/!ba;s#@1=#ID=#g}' f.sql >i.sql
至此得到下图的结构,接下来就时删除不需要的字段;