mysqlbinlog结合sed命令恢复update时未加where条件之前的数据

一.环境说明

腾讯云机器上自建MySQL 上update操作时,忘加where条件 ,使用mysqlbinlog搭配sed命令完美还原
MySQL版本号:5.6.39;
mysql必须开启binlog,并且mysql的binlog最好是Row模式;
mysql数据库指定字符集位utf8,同时表的字符集也得为utf8,否则在mysqlbinlog 解析出来的sql文件对于中文汉字的会出现乱码,导致最后恢复数据到线上的表中报错。
满足以上条件这样可以极大的保证数据恢复的几率。
当然把控好数据库的权限问题,禁止采用不加where条件的delete 和update语句,以及禁止采用drop,truncate才是从根源保证数据安全行之有效的办法。

前面的几篇博文都有介绍采用第三方的工具binlog-rollback.pl,binlog2sql来还原和恢复数据,其实原理和思路都是一致的。同时在测试使用中发现,这2个工具要求必须是本地数据库服务器安装此2个工具,本地的数据库开启binlog,binlog格式为Row模式并且都是针对本地数据库数据进行恢复的。如果在其他机器上安装binlog-rollback.pl或binlog2sql,并且其把要恢复数据的binlog文件拿到已经安装好binlog-rollback.pl或binlog2sql工具的机器上来恢复数据是会报错的,导致数据恢复失败。

二.采用mysqlbinlog结合sed命令依据binlog日志文件恢复数据

今天咱们介绍update执行时忘加where 条件,导致全表更新,采用mysqlbinlog结合sed命令依据binlog日志文件如何来恢复数据。采用此种方式恢复数据对mysql的服务和binlog文件所在的具体服务设备是没有任何限制的,此种方式恢复数据时更灵活

2.1确定binlog格式以及是否开启binlog

查看mysql的binlog格式:
show variables like ‘%binlog_format%‘;


查看是否开启了binlog
show variables like ‘%log_bin%‘;

我们可以看到log_bin的值为ON,开启状态,OK, 确保了update误操作前,我的数据库 是开启了binog并且binlog格式是row格式,我的数据库数据是可以还原的。
查看log文件:
show master logs;

2.2创建测试表

CREATE TABLE `zx_scores` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `titles` char(15) NOT NULL,
  `icon` smallint(6) unsigned DEFAULT ‘0‘,
  `integral` int(10) NOT NULL DEFAULT ‘0‘,
  `isdefault` tinyint(1) unsigned NOT NULL DEFAULT ‘0‘,
`create_time` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
`day` date NOT NULL DEFAULT ‘0000-00-00‘ COMMENT ‘日期‘,
  PRIMARY KEY (`id`),
  KEY `integral` (`integral`)
) ENGINE=Innodb AUTO_INCREMENT=0 DEFAULT CHARSET=utf8

给测试表插入数据:

insert into zx_scores values(1,‘列兵‘,1,0,1,now(),curdate());
insert into zx_scores values(2,‘班长‘,2,1000,1,now(),curdate());
insert into zx_scores values(3,‘少尉‘,3,2000,1,now(),curdate());
insert into zx_scores values(4,‘中尉‘,4,3000,1,now(),curdate());
insert into zx_scores values(5,‘上尉‘,5,4000,1,now(),curdate());
insert into zx_scores values(6,‘少校‘,6,5000,1,now(),curdate());
insert into zx_scores values(7,‘中校‘,7,6000,1,now(),curdate());
insert into zx_scores values(8,‘上校‘,8,7000,1,now(),curdate());
insert into zx_scores values(9,‘少将‘,9,12000,1,now(),curdate());
insert into zx_scores values(10,‘中将‘,10,17000,1,now(),curdate());
insert into zx_scores values(11,‘上将‘,11,22000,1,now(),curdate());
insert into zx_scores values(12,‘大将‘,12,27000,1,now(),curdate());

select * from test.zx_scores ;

update更新时忘记加where条件限制:
mysql> update zx_scores set titles=‘班长‘;
Query OK, 11 rows affected (0.00 sec)
Rows matched: 12 Changed: 11 Warnings: 0
mysql> select * from zx_scores ;

当前的binlog文件为如下:

mysql> show master status\G
*************************** 1. row ***************************
             File: mysql-bin.000020
         Position: 16042
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)

提示:把此binlog mysql-bin.000020文件移动到其他的机器上也是可以恢复的

三.腾讯云机器上采用mysqlbinog+sed命令来恢复

采用find查找到此文件在服务器上的位置:

[[email protected]_82_178_centos binlog]# find  / -name ‘mysql-bin.000020‘ ;
/data/mysql/binlog/mysql-bin.000020

找到这个文件,我们单独可以把他拷贝到tmp目录下,然返回到mysqllogbin这个文件路径下,再次之前需要确认一下你误操作的大概时间,因为我们要通过时间范围来搜索日志,执行命令如下:

mysqlbinlog  --base64-output=decode-rows   -v -v  --start-date=‘2018-10-07 15:25:00‘ --stop-date=‘2018-10-07 15:30:00‘  /tmp/mysql-bin.000020 | grep -C 30 "UPDATE `test`.`zx_scores`"

找到我们误操作的update 语句,记录下sql上面 # at 开头后面的数字14739(这个标记应该是事务的行号吧),OK,继续执行命令

/usr/local/mysql/bin/mysqlbinlog  --no-defaults  --base64-output=decode-rows  -v -v  /tmp/mysql-bin.000020|sed -n ‘/# at 14739/,/COMMIT/p‘  >/tmp/update.sql

我们将这串事务从# at 14739开始到COMMIT之间的行全部提取出来到update.sql里。

到此处,我们已经拿到了需要还原的sql语句,根据导出的sql语句进行sed命令替换,还原到修改之前sql语句,命令如下:

 sed ‘/WHERE/{:a;N;/SET/!ba;s/\([^\n]*\)\n\(.*\)\n\(.*\)/\3\n\2\n\1/}‘ update.sql | sed ‘s/### //g;s/\/\*.*/,/g‘ | sed  /@7/s/,//g | sed ‘/WHERE/{:a;N;/@7/!ba;s/,/AND/g};s/#.*//g;s/COMMIT,//g‘ | sed ‘/^$/d‘  >  rollback.sql

这里sed命令乍一看起来比较复杂,我们将它分成块来进行分析,因为sed命令是按顺序来执行的,上述命令一共由五条sed命令组成,通过管道分隔,下面我们来细说一下这些命令都做了什么:

3.1.第一个sed命令作用:

sed ‘/WHERE/{:a;N;/SET/!ba;s/\([^\n]*\)\n\(.*\)\n\(.*\)/\3\n\2\n\1/}‘ update.sql

功能:将where 和set位置对调
命令剖析:
/WHERE/ #包含WHERE

:a;      #创建一个labela;
N;       #追加下一个输入行到读取行的末尾,读入到模式空间
/SET/!ba;   # 如果不是/SET/,返回a,也就是重复读,一直读到/SET/之前(buffer的内容是WHERE\n.......\nSET)

s/([^\n])\n(.)\n(.*)/\3\n\2\n\1/ 这块可以分三部分来读

    第1步:
        s  #替换命令,例如s/a/b  将a替换为b
    第2步:
        \([^\n]*\)\n\(.*\)\n\(.*\)
        \        #转义字符
        [^\n]* == buffer中的where
        (.*\)    #单符号(.)匹配除换行符以外的单个字符,*同上;
         [^\n]*\  #代表非换行符(回车)开头,*表示匹配零或多个字符
        \n       #换行

    第3步
        \3\n\2\n\1
        \3  == 内存中的set,第三个括号中的内容
        \2  == 内存中原来where与set之间的内容,第二个括号中的内容
        \1  == 内存中的where,第一个括号中的内容
[[email protected]_82_178_centos tmp]#cp update.sql  sed1-update.sql
[[email protected]_82_178_centos tmp]# sed -i ‘/WHERE/{:a;N;/SET/!ba;s/\([^\n]*\)\n\(.*\)\n\(.*\)/\3\n\2\n\1/}‘ sed1-update.sql

将where 和set位置对调,update.sql文件中其他内容不变

3.2.第二个sed 命令作用:

 sed ‘s/### //g;s/\/\*.*/,/g‘

功能:这句做了两个事情1.把字符串### 替换成 空格 2.把/*往后的内容 替换成,


 s/### //g        #将### 替换成空串,
    \                #转义字符
    \/\*.*           #匹配/*之后出换行符外所有内容
[[email protected]_82_178_centos tmp]#cp  sed1-update.sql   sed2-update.sql
[[email protected]_82_178_centos tmp]# sed -i ‘s/### //g;s/\/\*.*/,/g‘ sed2-update.sql

内容如下:

[[email protected]_82_178_centos tmp]# grep -C 8 ‘UPDATE `test`.`zx_scores`‘ sed2-update.sql
.............
[[email protected]_82_178_centos tmp]# grep -C 8 ‘UPDATE `test`.`zx_scores`‘ sed2-update.sql|tail -26
UPDATE `test`.`zx_scores`
SET
  @1=11 ,
  @2=‘上将‘ ,
  @3=11 ,
  @4=22000 ,
  @5=1 ,
  @6=‘2018-10-07 15:20:30‘ ,
  @7=‘2018:10:07‘ ,
WHERE
  @1=11 ,
  @2=‘班长‘ ,
  @3=11 ,
  @4=22000 ,
  @5=1 ,
  @6=‘2018-10-07 15:20:30‘ ,
  @7=‘2018:10:07‘ ,
UPDATE `test`.`zx_scores`
SET
  @1=12 ,
  @2=‘大将‘ ,
  @3=12 ,
  @4=27000 ,
  @5=1 ,
  @6=‘2018-10-07 15:20:37‘ ,
  @7=‘2018:10:07‘ ,
[[email protected]_82_178_centos tmp]# 

3.3.第三个sed 命令作用:

 sed  /@7/s/,//g

功能:这句把字符串包含@7的行中的全部(,)换成空格

 /@7/     #匹配包含@7的行
 s/,//    #将,替换为空串
    g        #全部替换
[[email protected]_82_178_centos tmp]#cp  sed2-update.sql   sed3-update.sql
[[email protected]_82_178_centos tmp]# sed -i /@7/s/,//g sed3-update.sql

替换前文件内容:

[[email protected]_82_178_centos tmp]# grep ‘@7‘ sed2-update.sql |tail -5
  @7=‘2018:10:07‘ ,
  @7=‘2018:10:07‘ ,
  @7=‘2018:10:07‘ ,
  @7=‘2018:10:07‘ ,
  @7=‘2018:10:07‘ ,

替换后的文件内容:

[[email protected]_82_178_centos tmp]# grep ‘@7‘ sed3-update.sql |tail -5
  @7=‘2018:10:07‘
  @7=‘2018:10:07‘
  @7=‘2018:10:07‘
  @7=‘2018:10:07‘
  @7=‘2018:10:07‘ 

3.4.第四个sed 命令作用:


sed ‘/WHERE/{:a;N;/@7/!ba;s/,/AND/g};s/#.*//g;s/COMMIT,//g‘

功能:这句做了三件事 1.就是把WHERE 至@7之间的所有逗号,替换成AND 2.#.* 就是把#在的行替换为空格 3.就是把匹配到的COMMIT, 替换为空格

/WHERE/{:a;N;/@7/!ba;s/,/AND/g}      #将WHERE至@7之间的行尾的(,)替换为(AND)
        s/#.*//g                    #将#号开头的整行字符替换为空串。
        s/COMMIT,//g          #将(COMMIT,)替换为空行;
[[email protected]_82_178_centos tmp]#cp  sed3-update.sql   sed4-update.sql
[[email protected]_82_178_centos tmp]# sed -i ‘/WHERE/{:a;N;/@7/!ba;s/,/AND/g};s/#.*//g;s/COMMIT,//g‘ sed4-update.sql

替换后的文件的内容:

[[email protected]_82_178_centos tmp]# tail -20 sed4-update.sql
UPDATE `test`.`zx_scores`
SET
  @1=12 ,
  @2=‘大将‘ ,
  @3=12 ,
  @4=27000 ,
  @5=1 ,
  @6=‘2018-10-07 15:20:37‘ ,
  @7=‘2018:10:07‘
WHERE
  @1=12 AND
  @2=‘班长‘ AND
  @3=12 AND
  @4=27000 AND
  @5=1 AND
  @6=‘2018-10-07 15:20:37‘ AND
  @7=‘2018:10:07‘ 

3.5.第五个sed 命令:

sed ‘/^$/d‘   >  sed5-update.sql
 /^$/      #查找缓存内容中所有的空行
    d         #删除
 >  sed5-update.sql   #输出缓存中的内容到sed5-update.sql
[[email protected]_82_178_centos tmp]#cp  sed4-update.sql   sed5-update.sql
[[email protected]_82_178_centos tmp]# sed -i ‘/^$/d‘ sed5-update.sql

提示:对于第3个sed语句中的@7和第四个sed语句中@7可以替换成你当前表zx_score的最大列数@max。

3.6.第六个sed 命令:

sed  -i -r  ‘/WHERE/{:a;N;/@7/!ba;s/(@7=.*)/\1\;/g}‘ sed6-update.sql

这句是在where语句后@7最后一个字段加(;),如果后执行这句请将@7换成对应的列名即可。

[[email protected]_82_178_centos tmp]#cp  sed5-update.sql   sed6-update.sql
sed  -i -r  ‘/WHERE/{:a;N;/@7/!ba;s/(@7=.*)/\1\;/g}‘ sed6-update.sql ###此处采用的是后执行此命令

将sed6-update.sql中的@1,@2,@3,@4,@5,@6,@7替换成对应的列名

 sed -i ‘s/@1/列1/g;s/@2/列2/g;s/@3/列3/g;s/@4/列4/g;s/@5/列5/g;s/@6/列6/g;s/@7/列7/g‘   sed6-update.sql 

此处采用的是先把@1,@[email protected],@7替换为对应的zx_scores表的列名

[[email protected]_82_178_centos tmp]#  sed -i ‘s/@1/id/g;s/@2/titles/g;s/@3/icon/g;s/@4/integral/g;s/@5/isdefault/g;s/@6/create_time/g;s/@7/day/g‘   sed6-update.sql

换换后的内容如下:

[[email protected]_82_178_centos tmp]# tail -17 sed6-update.sql
UPDATE `test`.`zx_scores`
SET
  id=12 ,
  titles=‘大将‘ ,
  icon=12 ,
  integral=27000 ,
  isdefault=1 ,
  create_time=‘2018-10-07 15:20:37‘ ,
  day=‘2018:10:07‘
WHERE
  id=12 AND
  titles=‘班长‘ AND
  icon=12 AND
  integral=27000 AND
  isdefault=1 AND
  create_time=‘2018-10-07 15:20:37‘ AND
  day=‘2018:10:07‘ 

然后将@7转换为对应的列名day


sed  -i -r  ‘/WHERE/{:a;N;/@7/!ba;s/(@7=.*)/\1\;/g}‘ sed6-update.sql
[[email protected]_82_178_centos tmp]# sed  -i -r  ‘/WHERE/{:a;N;/day/!ba;s/(day=.*)/\1\;/g}‘ sed6-update.sql

转换后的内容如下:

[[email protected]_82_178_centos tmp]#  tail -17 sed6-update.sql
UPDATE `test`.`zx_scores`
SET
  id=12 ,
  titles=‘大将‘ ,
  icon=12 ,
  integral=27000 ,
  isdefault=1 ,
  create_time=‘2018-10-07 15:20:37‘ ,
  day=‘2018:10:07‘
WHERE
  id=12 AND
  titles=‘班长‘ AND
  icon=12 AND
  integral=27000 AND
  isdefault=1 AND
  create_time=‘2018-10-07 15:20:37‘ AND
  day=‘2018:10:07‘ ;

到此处数据还原已经完成,直接把sed6-update.sql 数据导入到mysql中即可

四.数据格式化

至此,我们的sql语句已经成功还原,美中不足的一条sql语句写成很多行,看起来不顺眼,来我们再继续优化下,执行语句:

[[email protected]_82_178_centos tmp]# cat sed6-update.sql | tr  "\n" " " > rollback.sql
将所有的换行替换成空格,此处用tr命令,因我的数据量比较大,tr执行效率相对较高,也可以用sed命令sed -i ‘:label;N;s/\n/ /;b label‘ rollback.sql,效果都是一样的
sed -i ‘s/\;/ LIMIT 1\;\n/g‘   rollback.sql

在每一个;前面加上 LIMIT 1,后面加上换行符:

[[email protected]_82_178_centos tmp]# sed -i ‘s/\;/ LIMIT 1\;\n/g‘ rollback.sql

恢复到MySQL

还原成功:

到此处mysqlbinlog结合sed命令恢复数据库数据介绍完毕,欢迎留言一起探讨交流学习

原文地址:http://blog.51cto.com/wujianwei/2294283

时间: 2024-08-02 14:37:10

mysqlbinlog结合sed命令恢复update时未加where条件之前的数据的相关文章

MySQL 误操作后数据恢复(update,delete忘加where条件)

在数据库日常维护中,开发人员是最让人头痛的,很多时候都会由于SQL语句写的有问题导致服务器出问题,导致资源耗尽.最危险的操作就是在做DML操作的时候忘加where条件,导致全表更新,这是作为运维或者DBA的我们改如何处理呢?下面我分别针对update和delete操作忘加where条件导致全表更新的处理方法. 一. update 忘加where条件误操作恢复数据(binglog格式必须是ROW) 1.创建测试用的数据表 mysql> create table t1 ( -> id int un

update忘了加where条件,不小心把oracle数据库里某张表的全表数据都更新了怎么办?

问题描述:数据库突然出问题了,一张物资价格表全部更新成了同一个价格,13万条数据 跟大家分享一下我自己跳的坑,希望对遇到类似问题的小伙伴有一点点帮助.ps:属于技术比较low的,所以自己进的坑比较深,解决方法可以直接看6和8 1.首先客户有数据库备份,每天凌晨都有数据库备份,我们没有dba权限,客户通过数据库监控日志查出18号有一个13万数据的update没有加where条件,给了我备份的数据库文件. 2.创建了新的表空间,表用户,导入18号的数据库(我的电脑上装了oracle服务) eg:创建

linux sed命令详解(转)

简介 sed 是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕.接着处理下一行,这样不断重复,直到文件末尾.文件内容并没有 改变,除非你使用重定向存储输出.Sed主要用来自动编辑一个或多个文件:简化对文件的反复操作:编写转换程序等. sed使用参数 [[email protected] ~]# sed [-nefr] [动作] 选项与参数: -n

2.2 linux sed命令详解

简介 sed 是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为"模式空间"(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕.接着处理下一行,这样不断重复,直到文件末尾.文件内容并没有 改变,除非你使用重定向存储输出.Sed主要用来自动编辑一个或多个文件:简化对文件的反复操作:编写转换程序等. sed使用参数 [[email protected] ~]# sed [-nefr] [动作] 选项与参数

sed命令手册

sed 是一种在线编辑器,它一次处理一行内容. 处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space). 接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕. 接着处理下一行,这样不断重复,直到文件末尾. 文件内容并没有 改变,除非你使用重定向存储输出. Sed主要用来自动编辑一个或多个文件:简化对文件的反复操作:编写转换程序等. -n, --quiet, --silent suppress automatic printing of pat

Ubuntu 14.10 下sed命令详解

简介 sed 是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕.接着处理下一行,这样不断重复,直到文件末尾.文件内容并没有 改变,除非你使用重定向存储输出.Sed主要用来自动编辑一个或多个文件:简化对文件的反复操作:编写转换程序等. sed使用参数 [[email protected] ~]# sed [-nefr] [动作] 选项与参数: -n

Linux sed命令实例详解

简介 sed 是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕.接着处理下一行,这样不断重复,直到文件末尾.文件内容并没有 改变,除非你使用重定向存储输出.Sed主要用来自动编辑一个或多个文件:简化对文件的反复操作:编写转换程序等. sed使用参数 [[email protected] ~]# sed [-nefr] [动作] 选项与参数: -n

sed命令使用详解

[[email protected] ~]# sed [-nefr] [动作] 选项与参数:-n :使用安静(silent)模式.在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到终端上.但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来.-e :直接在命令列模式上进行 sed 的动作编辑:-f :直接将 sed 的动作写在一个文件内, -f filename 则可以运行 filename 内的 sed 动作:-r :sed 的动作支持的是延

Linux安全基础:sed命令的使用

sed 是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换.删除.新增.选取等特定工作. Sed本质上是一个编辑器,但是它是非交互式的,这点与VIM不同:同时它又是面向字符流的,输入的字符流经过Sed的处理后输出.这两个特性使得Sed成为命令行下面非常有用的一个处理工具. sed 参数[-nefr] 动作[function] 文件 选项与参数: -n :使用安静(silent)模式.在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到