通过binlog恢复误delete的数据(一)

文章目录

    • 1.1 先说明故障
    • 1.2 数据库环境
    • 1.3 源数据模拟
    • 1.4 故障模拟
    • 1.5 解决思路
    • 1.6 故障处理步骤

1.1 先说明故障

01:生产环境上,使用delete命令删除了一条记录(数据),条件指定错球了;
02:生产环境上是开启了binlog日志的,模式为row模式;
03:需要马上进行数据的恢复;

1.2 数据库环境

#### 数据库版本、binlog的配置
mysql> select @@version,@@global.log_bin,@@global.log_bin_basename,@@binlog_format;
+------------+------------------+------------------------------------------+-----------------+
| @@version  | @@global.log_bin | @@global.log_bin_basename                | @@binlog_format |
+------------+------------------+------------------------------------------+-----------------+
| 5.7.28-log |                1 | /data/mysql/3306/logs/binlog/21_mysql_bin| ROW             |
+------------+------------------+------------------------------------------+-----------------+
1 row in set (0.00 sec)


#### binlog的其它配置
mysql> select @@global.binlog_row_image,@@binlog_rows_query_log_events;
+---------------------------+--------------------------------+
| @@global.binlog_row_image | @@binlog_rows_query_log_events |
+---------------------------+--------------------------------+
| FULL                      |                              1 |
+---------------------------+--------------------------------+
1 row in set (0.00 sec)


#### 特别说明
binlog_row_image 
  # 默认值是full,针对row模式的binlog,对inset\update\delete语句进行详细的记录
  
binlog_rows_query_log_events
  # 默认值是off,针对row模式,可在线设置,若为on可以在mysql中用show binlog events in "二进制日志文件名";
  # 命令查看二进制日志文件中记录的DML语句和其它信息;


#### 当前binlog日志的状态
mysql> show master status\G
*************************** 1. row ***************************
             File: 21_mysql_bin.000001
         Position: 154
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 
1 row in set (0.00 sec)


1.3 源数据模拟

#### 创建lili库,并进入到lili库下面
create database if not exists lili character set utf8 collate utf8_general_ci;
use lili;


#### 创建test1表
create table if not exists test1(
  id int unsigned not null auto_increment comment"序列",
  name varchar(20) not null comment"姓名",
  sex enum("男","女") not null comment"性别",
  age tinyint unsigned not null comment"年龄",
  height float(5,2) not null comment"身高",
  weight float(5,2) not null comment"体重",
  gr_sc varchar(30) not null comment"毕业院校",
  education varchar(10) not null comment"学历",
  phone char(11) not null comment"电话号码",
  email varchar(30) not null comment"邮箱",
  salary float(9,2) unsigned not null comment"薪资",
  primary key(id)
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表1";


#### 查看test1表的表结构
mysql> desc test1;
+-----------+---------------------+------+-----+---------+----------------+
| Field     | Type                | Null | Key | Default | Extra          |
+-----------+---------------------+------+-----+---------+----------------+
| id        | int(10) unsigned    | NO   | PRI | NULL    | auto_increment |
| name      | varchar(20)         | NO   |     | NULL    |                |
| sex       | enum('男','女')      | NO   |     | NULL    |                |
| age       | tinyint(3) unsigned | NO   |     | NULL    |                |
| height    | float(5,2)          | NO   |     | NULL    |                |
| weight    | float(5,2)          | NO   |     | NULL    |                |
| gr_sc     | varchar(30)         | NO   |     | NULL    |                |
| education | varchar(10)         | NO   |     | NULL    |                |
| phone     | char(11)            | NO   |     | NULL    |                |
| email     | varchar(30)         | NO   |     | NULL    |                |
| salary    | float(9,2) unsigned | NO   |     | NULL    |                |
+-----------+---------------------+------+-----+---------+----------------+
11 rows in set (0.01 sec)
    # 注意test1表的id字段是auto_increment(自增)的,且有主键索引;
    # 注意test1表的sex字段是enum数据类型


#### 往test1表中插入几条数据
insert into test1(name,sex,age,height,weight,gr_sc,education,phone,email,salary) values
("cl01","男",21,171,65.5,"四川信息1","专科","18382024221","[email protected]",6000),
("cl02","男",22,172,65.5,"四川信息2","专科","18382024222","[email protected]",6200),
("cl03","男",23,173,65.5,"四川信息3","专科","18382024223","[email protected]",6300),
("cl04","男",24,174,65.5,"四川信息4","专科","18382024224","[email protected]",6400),
("cl05","男",25,175,65.5,"四川信息5","专科","18382024225","[email protected]",6500),
("cl06","男",26,176,65.5,"四川信息6","专科","18382024226","[email protected]",6600),
("cl07","男",27,177,65.5,"四川信息7","专科","18382024227","[email protected]",6700),
("cl08","男",28,178,65.5,"四川信息8","专科","18382024228","[email protected]",6800),
("cl09","男",29,179,65.5,"四川信息9","专科","18382024229","[email protected]",6900),
("cl10","男",30,180,65.5,"四川信息10","专科","18382024230","[email protected]",7000);
commit;


#### 查看test1表中的数据
mysql> select * from test1;
+----+------+-----+-----+--------+--------+----------------+-----------+-------------+------------------+---------+
| id | name | sex | age | height | weight | gr_sc          | education | phone       | email            | salary  |
+----+------+-----+-----+--------+--------+----------------+-----------+-------------+------------------+---------+
|  1 | cl01 ||  21 | 171.00 |  65.50 | 四川信息1        | 专科      | 18382024221 | 158317096@qq.com | 6000.00 |
|  2 | cl02 ||  22 | 172.00 |  65.50 | 四川信息2        | 专科      | 18382024222 | 158317096@qq.com | 6200.00 |
|  3 | cl03 ||  23 | 173.00 |  65.50 | 四川信息3        | 专科      | 18382024223 | 158317096@qq.com | 6300.00 |
|  4 | cl04 ||  24 | 174.00 |  65.50 | 四川信息4        | 专科      | 18382024224 | 158317096@qq.com | 6400.00 |
|  5 | cl05 ||  25 | 175.00 |  65.50 | 四川信息5        | 专科      | 18382024225 | 158317096@qq.com | 6500.00 |
|  6 | cl06 ||  26 | 176.00 |  65.50 | 四川信息6        | 专科      | 18382024226 | 158317096@qq.com | 6600.00 |
|  7 | cl07 ||  27 | 177.00 |  65.50 | 四川信息7        | 专科      | 18382024227 | 158317096@qq.com | 6700.00 |
|  8 | cl08 ||  28 | 178.00 |  65.50 | 四川信息8        | 专科      | 18382024228 | 158317096@qq.com | 6800.00 |
|  9 | cl09 ||  29 | 179.00 |  65.50 | 四川信息9        | 专科      | 18382024229 | 158317096@qq.com | 6900.00 |
| 10 | cl10 ||  30 | 180.00 |  65.50 | 四川信息10       | 专科      | 18382024230 | 158317100@qq.com | 7000.00 |
+----+------+-----+-----+--------+--------+----------------+-----------+-------------+------------------+---------+
10 rows in set (0.00 sec)


1.4 故障模拟

####  删除id等于10的记录
mysql> select * from test1 where id=10; 
+----+------+-----+-----+--------+--------+----------------+-----------+-------------+------------------+---------+
| id | name | sex | age | height | weight | gr_sc          | education | phone       | email            | salary  |
+----+------+-----+-----+--------+--------+----------------+-----------+-------------+------------------+---------+
| 10 | cl10 ||  30 | 180.00 |  65.50 | 四川信息10       | 专科      | 18382024230 | 158317100@qq.com | 7000.00 |
+----+------+-----+-----+--------+--------+----------------+-----------+-------------+------------------+---------+
1 row in set (0.00 sec)

mysql> delete from test1 where id=10;      # 删除test1表中id等于10的记录
Query OK, 1 row affected (0.00 sec)

mysql> select * from test1 where id=10;     # 查看test1表中id等于10的记录是否删除成功
Empty set (0.00 sec)


                  PS:业务还在产生数据


#### 往test1表中再插入数据
insert into test1(name,sex,age,height,weight,gr_sc,education,phone,email,salary) values
("chenliang01","男",21,171,65.5,"四川信息1","专科","18382024221","[email protected]",6000);
commit;


#### 查看test1表中的数据
mysql> select * from test1;
+----+-------------+-----+-----+--------+--------+---------------+-----------+-------------+------------------+---------+
| id | name        | sex | age | height | weight | gr_sc         | education | phone       | email            | salary  |
+----+-------------+-----+-----+--------+--------+---------------+-----------+-------------+------------------+---------+
|  1 | cl01        ||  21 | 171.00 |  65.50 | 四川信息1       | 专科      | 18382024221 | 158317096@qq.com | 6000.00 |
|  2 | cl02        ||  22 | 172.00 |  65.50 | 四川信息2       | 专科      | 18382024222 | 158317096@qq.com | 6200.00 |
|  3 | cl03        ||  23 | 173.00 |  65.50 | 四川信息3       | 专科      | 18382024223 | 158317096@qq.com | 6300.00 |
|  4 | cl04        ||  24 | 174.00 |  65.50 | 四川信息4       | 专科      | 18382024224 | 158317096@qq.com | 6400.00 |
|  5 | cl05        ||  25 | 175.00 |  65.50 | 四川信息5       | 专科      | 18382024225 | 158317096@qq.com | 6500.00 |
|  6 | cl06        ||  26 | 176.00 |  65.50 | 四川信息6       | 专科      | 18382024226 | 158317096@qq.com | 6600.00 |
|  7 | cl07        ||  27 | 177.00 |  65.50 | 四川信息7       | 专科      | 18382024227 | 158317096@qq.com | 6700.00 |
|  8 | cl08        ||  28 | 178.00 |  65.50 | 四川信息8       | 专科      | 18382024228 | 158317096@qq.com | 6800.00 |
|  9 | cl09        ||  29 | 179.00 |  65.50 | 四川信息9       | 专科      | 18382024229 | 158317096@qq.com | 6900.00 |
| 11 | chenliang01 ||  21 | 171.00 |  65.50 | 四川信息1       | 专科      | 18382024221 | 158317096@qq.com | 6000.00 |
+----+-------------+-----+-----+--------+--------+---------------+-----------+-------------+------------------+---------+
10 rows in set (0.00 sec)


1.5 解决思路

01:在得知使用delete语句误删除了数据,这里是一条记录哈;需要做的事情:
    A:使用show master status;命令查看看当前binlog是哪个文件,并记录下来;
    B:执行flush logs命令重新生成新的binlog日志文件来记录sql语句产生的记录;
    C:确定删除数据的命令是什么,这里是:delete from test1 where id=10;
    
02:对“01阶段”中的“A步骤”中的binlog日志做备份(复制一份到其它目录下,防止损坏源binlog文件);

03:在mysql中使用"show binlog events in "01阶段中A步骤记录的binlog文件名";"命令找到
    delete from test1 where id=10;这条语句(事务)的起始pos点和结束pos点;
    
04:用mysqlbinlog命令结合"03阶段"找到的起始pos点和结束pos点对"02步骤"复制的binlog文件
    进行解释并生成新的文件;
    
05:在“04阶段”中新生成的文件中进行处理,这里要结合到test1表的表结构来进行处理哈;

06:恢复06阶段处理好的sql语句;


1.6 故障处理步骤

解决思路中的01阶段

#### 查看当前binlog日志文件是哪个
mysql> show master status\G
*************************** 1. row ***************************
             File: 21_mysql_bin.000001
         Position: 4210
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 
1 row in set (0.00 sec)


#### 使用flush logs命令重新生成新的binlog命令
mysql> flush logs;
Query OK, 0 rows affected (0.00 sec)

mysql> show master status\G
*************************** 1. row ***************************
             File: 21_mysql_bin.000002
         Position: 154
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 
1 row in set (0.00 sec)


解决思路中的02阶段

[root@node21 ~]# cp -a /data/mysql/3306/logs/binlog/21_mysql_bin.000001 /tmp/
[root@node21 ~]# ll /tmp/21_mysql_bin.000001 
-rw-r----- 1 mysql mysql 2335 7月   1 08:06 /tmp/21_mysql_bin.000001


解决思路中的03阶段
通过binlog恢复误delete的数据(一)_第1张图片
最终的结果:起始pos点3235;结束pos点3642


解决思路中的04阶段

## 进入到之前备份binlog文件的目录
[root@node21 tmp]# pwd
/tmp
[root@node21 tmp]# ll 21_mysql_bin.000001 
-rw-r----- 1 mysql mysql 2017 3月   3 19:22 21_mysql_bin.000001

## 对binlog日志进行解释并保存到a.txt文件中
[root@node21 tmp]# mysqlbinlog --base64-output=decode-rows -vv \
--start-position=3235 --stop-position=3642 21_mysql_bin.000001 >a.txt


解决思路中的05阶段

############################## 处理 a.txt 文件,生成 b.txt 文件 #######################
[root@node21 tmp]# sed -n '/^###/'p a.txt  >b.txt
[root@node21 tmp]# cat b.txt 
### DELETE FROM `lili`.`test1`
### WHERE
###   @1=10 /* INT meta=0 nullable=0 is_null=0 */
###   @2='cl10' /* VARSTRING(60) meta=60 nullable=0 is_null=0 */
###   @3=1 /* ENUM(1 byte) meta=63233 nullable=0 is_null=0 */
###   @4=30 /* TINYINT meta=0 nullable=0 is_null=0 */
###   @5=180                  /* FLOAT meta=4 nullable=0 is_null=0 */
###   @6=65.5                 /* FLOAT meta=4 nullable=0 is_null=0 */
###   @7='四川信息10' /* VARSTRING(90) meta=90 nullable=0 is_null=0 */
###   @8='专科' /* VARSTRING(30) meta=30 nullable=0 is_null=0 */
###   @9='18382024230' /* STRING(33) meta=65057 nullable=0 is_null=0 */
###   @10='[email protected]' /* VARSTRING(90) meta=90 nullable=0 is_null=0 */
###   @11=7000                 /* FLOAT meta=4 nullable=0 is_null=0 */


############################## 处理 b.txt 文件,生成 c.txt 文件 #######################
[root@node21 tmp]# sed 's/### //g' b.txt >c.txt
[root@node21 tmp]# cat c.txt 
DELETE FROM `lili`.`test1`
WHERE
  @1=10 /* INT meta=0 nullable=0 is_null=0 */
  @2='cl10' /* VARSTRING(60) meta=60 nullable=0 is_null=0 */
  @3=1 /* ENUM(1 byte) meta=63233 nullable=0 is_null=0 */
  @4=30 /* TINYINT meta=0 nullable=0 is_null=0 */
  @5=180                  /* FLOAT meta=4 nullable=0 is_null=0 */
  @6=65.5                 /* FLOAT meta=4 nullable=0 is_null=0 */
  @7='四川信息10' /* VARSTRING(90) meta=90 nullable=0 is_null=0 */
  @8='专科' /* VARSTRING(30) meta=30 nullable=0 is_null=0 */
  @9='18382024230' /* STRING(33) meta=65057 nullable=0 is_null=0 */
  @10='[email protected]' /* VARSTRING(90) meta=90 nullable=0 is_null=0 */
  @11=7000                 /* FLOAT meta=4 nullable=0 is_null=0 */


############################## 处理 c.txt 文件,生成 d.txt 文件 #######################
[root@node21 tmp]# sed 's#/.*#,#g' c.txt >d.txt
[root@node21 tmp]# cat d.txt 
DELETE FROM `lili`.`test1`
WHERE
  @1=10 ,
  @2='cl10' ,
  @3=1 ,
  @4=30 ,
  @5=180                  ,
  @6=65.5                 ,
  @7='四川信息10' ,
  @8='专科' ,
  @9='18382024230' ,
  @10='[email protected]' ,
  @11=7000                 ,


############################## 处理 d.txt 文件,生成 e.txt 文件 #######################
[root@node21 tmp]# sed 's#DELETE FROM#INSERT INTO#g' d.txt >e.txt
[root@node21 tmp]# cat e.txt 
INSERT INTO `lili`.`test1`
WHERE
  @1=10 ,
  @2='cl10' ,
  @3=1 ,
  @4=30 ,
  @5=180                  ,
  @6=65.5                 ,
  @7='四川信息10' ,
  @8='专科' ,
  @9='18382024230' ,
  @10='[email protected]' ,
  @11=7000                 ,


############################## 处理 e.txt 文件,生成 f.txt 文件 #######################
[root@node21 tmp]# sed 's#WHERE#SELECT#g' e.txt >f.txt
[root@node21 tmp]# cat f.txt 
INSERT INTO `lili`.`test1`
SELECT
  @1=10 ,
  @2='cl10' ,
  @3=1 ,
  @4=30 ,
  @5=180                  ,
  @6=65.5                 ,
  @7='四川信息10' ,
  @8='专科' ,
  @9='18382024230' ,
  @10='[email protected]' ,
  @11=7000                 ,


############################## 处理 f.txt 文件,生成 h.txt 文件 #######################
[root@node21 tmp]# sed -r 's#(@11=.*)(,)#\1;#g' f.txt >h.txt
[root@node21 tmp]# cat h.txt 
INSERT INTO `lili`.`test1`
SELECT
  @1=10 ,
  @2='cl10' ,
  @3=1 ,
  @4=30 ,
  @5=180                  ,
  @6=65.5                 ,
  @7='四川信息10' ,
  @8='专科' ,
  @9='18382024230' ,
  @10='[email protected]' ,
  @11=7000                 ;


############################## 处理 h.txt 文件,生成 aa.sql 文件 ######################
[root@node21 tmp]# sed -r 's#(@.*=)(.*)#\2#g' h.txt >>aa.sql
[root@node21 tmp]# cat aa.sql 
INSERT INTO `lili`.`test1`
SELECT
  10 ,
  'cl10' ,
  1 ,
  30 ,
  180                  ,
  65.5                 ,
  '四川信息10' ,
  '专科' ,
  '18382024230' ,
  '[email protected]' ,
  7000                 ;


############################## 在aa.sql文件后面添加commit;命令 ####################
[root@node21 tmp]# sed -i '$a commit;' aa.sql 
[root@node21 tmp]# cat aa.sql 
INSERT INTO `lili`.`test1`
SELECT
  10 ,
  'cl10' ,
  1 ,
  30 ,
  180                  ,
  65.5                 ,
  '四川信息10' ,
  '专科' ,
  '18382024230' ,
  '[email protected]' ,
  7000                 ;
commit;


解决思路中的07阶段

#### 将aa.sql文件中的语句在数据库中进行执行
mysql> INSERT INTO `lili`.`test1`
    -> SELECT
    ->   10 ,
    ->   'cl10' ,
    ->   1 ,
    ->   30 ,
    ->   180                  ,
    ->   65.5                 ,
    ->   '四川信息10' ,
    ->   '专科' ,
    ->   '18382024230' ,
    ->   '[email protected]' ,
    ->   7000                 ;
Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)


#### 查看数据是否成功恢复到test1表中
mysql> select * from lili.test1 where id=10;
+----+------+-----+-----+--------+--------+----------------+-----------+-------------+------------------+---------+
| id | name | sex | age | height | weight | gr_sc          | education | phone       | email            | salary  |
+----+------+-----+-----+--------+--------+----------------+-----------+-------------+------------------+---------+
| 10 | cl10 ||  30 | 180.00 |  65.50 | 四川信息10       | 专科      | 18382024230 | [email protected] | 7000.00 |
+----+------+-----+-----+--------+--------+----------------+-----------+-------------+------------------+---------+
1 row in set (0.00 sec)

你可能感兴趣的:(#,mysql,5.7.X)