51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

删库了别跑路 你还应该学会如何恢复数据

# 前言 {#前言}

首先问大家一个问题,如果你上生产的代码在执行delete的时候跳过了where条件,或者执行update时忘记加where条件了,导致大量数据被删除或更新,你会如何处理?

上面的这些问题可能会导致很多数据被错误的更新或删除,当遇到这种情况时,用开玩笑的说法来说只能删库跑路,而更应该学会的是如何将这些数据恢复。

# 数据安全策略 {#数据安全策略}

为了保证数据的安全性,DBA一般会对数据库做下面这两个操作

  1. 对数据库进行定期备份:这个操作可能是一天一次,也可能是一周一次,频率越高,恢复的速度越快。
  2. 开启binlog日志:binlog日志可以做很多事情,比如在主从同步过程中,作为从库的数据来源,又比如在数据丢失的情况下做数据恢复。

通过下面的命令查看是否开启binlog日志

SHOW VARIABLES LIKE 'log_bin';

1

输出结果为on则代表binlog日志被开启

# 数据恢复流程演示 {#数据恢复流程演示}

本次演示基于MySQL8.0.45,数据库引擎为InnoDB

# 创建数据 {#创建数据}

首先创建一张表,并往这张表里插入两条数据:

CREATE TABLE `test_person` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `school` varchar(255) DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  `age` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

INSERT INTO `test`.`test_person` (`id`, `name`, `school`, `address`, `age`) VALUES (1, 'aa', 'testSchool', 'hz', 25);
INSERT INTO `test`.`test_person` (`id`, `name`, `school`, `address`, `age`) VALUES (2, 'bb', 'testSchool2', 'sh', 26); 

1
2
3
4
5
6
7
8
9
10
11
12

# 备份数据 {#备份数据}

接着模拟日常的备份动作,通过mysqldump命令进行数据备份

./mysqldump --single-transaction --flush-logs --source-data=2 --routines --opt -uroot -p test > backup.sql

1

下面是每个参数的含义:

--single-transaction:表示在备份过程中,使用单个事务来确保数据的一致性。

--flush-logs:表示在备份过程中,刷新日志文件,以便在备份完成后,日志文件中的内容不会影响到备份数据。

--source-data=2:表示在备份过程中,将主服务器的二进制日志位置信息也备份到文件中。这个参数比较重要,用于在恢复数据时找到位置信息。老版本叫做master-data

--routines:表示在备份过程中,备份存储过程和函数。

--opt:表示使用优化过的备份方式,以提高备份速度和减少备份文件的大小。

执行完成上面的命令之后,会发现多了一个backup.sql的文件

# 模拟数据的删除 {#模拟数据的删除}

接着在数据库中执行数据删除,模拟数据被误删

DELETE FROM test_person where 1=1

1

# 进行数据恢复 {#进行数据恢复}

当发现数据被删除之后,此时就需要进行紧急数据恢复了,数据恢复的原理就是以定期备份文件为全量基础,加上binlog的增量数据,从而恢复数据到任何一秒。

首先需要从备份文件中找到最后的binlog写入位置:

cat backup.sql | grep 'CHANGE MASTER TO MASTER_LOG_FILE'

1

以上图为例,可以看到备份文件一直包含了mysql-bin.000007的157这个位置,意味着增量恢复只需要从157这个位置开始即可。 接着找到删除语句执行的位置

./mysqlbinlog --no-defaults -vv /usr/local/mysql/data/mysql-bin.000007 | grep -i -B 4 'delete from test_person'

1

从上面的命令可以看出,这条删除命令对应的binlog执行的位置是从318到428

从157到318的这中间的数据就是增量的数据,将这些数据整理成增量sql

./mysqlbinlog  --no-defaults --start-position=157 --stop-position=318 /usr/local/mysql/data/mysql-bin.000007 > backup_inc.sql

1

执行完成后,服务器上已经有backup.sql和backup_inc.sql两个文件了

分别执行下面两段sql进行数据恢复:

./mysql -uroot -p test < backup.sql
./mysql -uroot -p test < backup_inc.sql

1
2

再次运行查找语句会发现被删除的数据已经回来了。

# 举一反三 {#举一反三}

删除数据之后,可能还会有不少语句已经执行了,如果要将后续的数据也补上,要怎么实现呢?

也很简单,上面删除语句的执行位置是从318到428,那只需要将428之后的sql整理出来执行就行:

./mysqlbinlog  --no-defaults --start-position=428 /usr/local/mysql/data/mysql-bin.000007 > backup_inc2.sql

1

# 总结 {#总结}

这是一个值得学习的技能,也是一个最好永远不要用到的技能。不过了解数据恢复会加深对binlog日志的认识,也不错。

赞(5)
未经允许不得转载:工具盒子 » 删库了别跑路 你还应该学会如何恢复数据