使用binlog从MySQL恢复已删除的数据

当在MySQL中误删数据时,可以通过启用binlog并使用mysqlbinlog工具来恢复。首先确保binlog-format为ROW,并配置log-bin路径。通过分析binlog事件,找到删除记录的位置,然后使用mysqlbinlog提取并手动或通过MyUndelete脚本恢复数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当我们意外地基于MySQL运行错误的查询时该怎么办?是否可以从MySQL恢复已删除的数据?如果我们使用binlog,例如我们在MySQL复制中使用的binlog,我们可以对此做一些事情。

您正在查看的文章超过2年。请记住,其中的某些信息可能已经过时。

为了从MySQL恢复数据,我们将使用以ROW模式运行的宾果游戏。如果我们删除了一条记录但未启用它,则将无法恢复丢失的数据。在中/etc/my.cnf,应设置以下参数:

binlog-format = ROW
log-bin = /var/log/mysql/bin-log

我们将创建一个测试数据库并用记录完成它。

CREATE DATABASE `undelete`;
USE `undelete`;

CREATE TABLE `names` (
	`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
	`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
	`name` varchar(20) DEFAULT NULL,
	PRIMARY KEY (`id`)
) ENGINE=InnoDB;

INSERT INTO `names` (name) VALUES ("Kamil"), ("Michal"), ("Adam"), ("Gerard"), ("Bartek");

我们创建了一个带有名称表的未删除数据库,该表包含五个记录。可以肯定的是,让我们检查其内容:

mysql> select * from names;
+----+---------------------+--------+
| id | date                | name   |
+----+---------------------+--------+
|  1 | 2015-02-14 09:12:42 | Kamil  |
|  2 | 2015-02-14 09:12:42 | Michal |
|  3 | 2015-02-14 09:12:42 | Adam   |
|  4 | 2015-02-14 09:12:42 | Gerard |
|  5 | 2015-02-14 09:12:42 | Bartek |
+----+---------------------+--------+
5 rows in set (0.00 sec)

我们将从数据库中删除随机记录,然后尝试恢复它们。

mysql> DELETE FROM `names` WHERE id >3;
Query OK, 2 rows affected (0.00 sec)

mysql> select * from names;
+----+---------------------+--------+
| id | date                | name   |
+----+---------------------+--------+
|  1 | 2015-02-14 09:12:42 | Kamil  |
|  2 | 2015-02-14 09:12:42 | Michal |
|  3 | 2015-02-14 09:12:42 | Adam   |
+----+---------------------+--------+
3 rows in set (0.00 sec)

正如您在上面看到的,我们设法删除了两条记录。此信息应保存在我们将从中检索数据的宾果游戏中。在我们的例子中,它是一个bin-log.000001文件。

mysql> show binlog events in 'bin-log.000001';
+----------------+-----+-------------+-----------+-------------+---------------------------------------+
| Log_name       | Pos | Event_type  | Server_id | End_log_pos | Info                                  |
+----------------+-----+-------------+-----------+-------------+---------------------------------------+
| bin-log.000001 |   4 | Format_desc |         1 |         120 | Server ver: 5.6.22-log, Binlog ver: 4 |
| bin-log.000001 | 120 | Query       |         1 |         196 | BEGIN                                 |
| bin-log.000001 | 196 | Table_map   |         1 |         253 | table_id: 73 (undelete.names)         |
| bin-log.000001 | 253 | Delete_rows |         1 |         320 | table_id: 73 flags: STMT_END_F        |
| bin-log.000001 | 320 | Xid         |         1 |         351 | COMMIT /* xid=78 */                   |
+----------------+-----+-------------+-----------+-------------+---------------------------------------+

用mysqlbinlog恢复

可以使用mysqlbinlog命令手动执行数据恢复操作。它使我们能够怀疑存储在二进制日志中的数据。

mysqlbinlog -v --base64-output=DECODE-ROWS --start-position=196 /var/log/mysql/bin-log.000001
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 196
#150215  9:36:32 server id 1  end_log_pos 253 CRC32 0x6bedb0e7 	Table_map: `undelete`.`names` mapped to number 73
# at 253
#150215  9:36:32 server id 1  end_log_pos 320 CRC32 0x1bc278f9 	Delete_rows: table id 73 flags: STMT_END_F
### DELETE FROM `undelete`.`names`
### WHERE
###   @1=4
###   @2=1423992931
###   @3='Gerard'
### DELETE FROM `undelete`.`names`
### WHERE
###   @1=5
###   @2=1423992931
###   @3='Bartek'
# at 320
#150215  9:36:32 server id 1  end_log_pos 351 CRC32 0xee833dd0 	Xid = 78
COMMIT/*!*/;
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

如果没有太多数据,我们可以将它们手动移动到数据库中。如果数量很多,我们可以尝试使用MyUndelete之类的脚本。

使用MyUndelete恢复

下载脚本https://download.csdn.net/download/bill20100829/15402393。我们还需要修改文件vim〜/ .my.cnf,其中包含用于登录数据库的数据。

在我们的例子中,数据删除是在binog 120和351中的位置之间发生的。因此,我们发出了一条适当的命令,希望可以恢复数据:

./MyUndelete.py -b /var/log/mysql/bin-log.000001 -s 120 -e 351

*** WARNING *** USE WITH CARE ****

Binlog file is  /var/log/mysql/bin-log.000001
Start Position file is  120
End Postision file is  351
Event type (' ') is a delete v2
Ready to revert the statement ? [y/n]
y
Done... I hope it worked ;)

现在,我们可以在数据库中检查结果。如下所示,数据已还原。

<span style="color:#475978"><code>mysql> use undelete;
Database changed
mysql> select * from names;
+----+---------------------+--------+
| id | date                | name   |
+----+---------------------+--------+
|  1 | 2015-02-15 09:35:31 | Kamil  |
|  2 | 2015-02-15 09:35:31 | Michal |
|  3 | 2015-02-15 09:35:31 | Adam   |
|  4 | 2015-02-15 09:35:31 | Gerard |
|  5 | 2015-02-15 09:35:31 | Bartek |
+----+---------------------+--------+
5 rows in set (0.00 sec)</code></span>

该脚本还允许在基于错误的INSERT和UPDATE命令执行的情况下撤消数据。

语法

MyUndelete.py -b <binlog> -s <start position> -e <end position> [-i] [-u]

  -b | --binlog=  : path of the binary log file
  -s | --start=   : start position
  -e | --end=     : stop position
  -i | --insert   : consider also INSERT statements (by default, only DELETE)
  -u | --update   : consider also UPDATE statements (by default, only DELETE)
  -d | --debug    : add debug messages

Info: The program expects that you have read access to the binary log
and you have all eventual MySQL credential in ~/.my.cnf

例子

取消删除

mysql> select * from fred;
+----+------------+
| id | name       |
+----+------------+
|  1 | Fred       |
|  2 | Jen        |
|  3 | Wilhelmine |
|  4 | Héloïse    |
|  5 | Suhi       |
+----+------------+
5 rows in set (0.00 sec)

mysql> delete from fred where id >3;
Query OK, 2 rows affected (0.04 sec)

mysql> select * from fred;
+----+------------+
| id | name       |
+----+------------+
|  1 | Fred       |
|  2 | Jen        |
|  3 | Wilhelmine |
+----+------------+
3 rows in set (0.00 sec)

mysql> show binlog events in 'mysql-bin.000008';
+------------------+------+-------------+-----------+-------------+---------------------------------------+
| Log_name         | Pos  | Event_type  | Server_id | End_log_pos | Info                                  |
+------------------+------+-------------+-----------+-------------+---------------------------------------+
...
| mysql-bin.000008 | 1514 | Query       |         1 |        1586 | BEGIN                                 |
| mysql-bin.000008 | 1586 | Table_map   |         1 |        1636 | table_id: 72 (fred.fred)              |
| mysql-bin.000008 | 1636 | Delete_rows |         1 |        1694 | table_id: 72 flags: STMT_END_F        |
| mysql-bin.000008 | 1694 | Xid         |         1 |        1725 | COMMIT /* xid=146 */                  |
+------------------+------+-------------+-----------+-------------+---------------------------------------+

$ sudo ./MyUndelete.py  -b /var/lib/mysql/mysql-bin.000008 -s 1514 -e 1725

*** WARNING *** USE WITH CARE ****

Binlog file is  /var/lib/mysql/mysql-bin.000008
Start Position file is  1514
End Postision file is  1725
Event type (' ') is a delete v2
Ready to revert the statement ? [y/n]
y
Done... I hope it worked ;)

mysql> select * from fred;
+----+------------+
| id | name       |
+----+------------+
|  1 | Fred       |
|  2 | Jen        |
|  3 | Wilhelmine |
|  4 | Héloïse    |
|  5 | Suhi       |
+----+------------+
5 rows in set (0.00 sec)

取消插入

删除在positon 41989和42207之间的二进制日志mysqld-bin.000004中发生的插入。

$ sudo ./MyUndelete.py -s 41989 -e 42207 -i -b /var/lib/mysql/mysqld-bin.000004

*** WARNING *** USE WITH CARE ****

Binlog file is  /var/lib/mysql/mysqld-bin.000004
Start Position file is  41989
End Postision file is  42207
We also look to undo INSERTs
Event type ('\x1e') is an insert v2
Ready to revert the statement ? [y/n]
y
Done... I hope it worked ;)

取消更新

让我们修改一些记录,然后还原更改:

mysql> select * from fred;
+----+------------+
| id | name       |
+----+------------+
|  1 | Fred       |
|  2 | Jen        |
|  3 | Wilhelmine |
|  4 | Héloïse    |
|  5 | Suhi       |
+----+------------+
mysql> update fred set name = concat(name, "2") where id >3;
Query OK, 2 rows affected (0.03 sec)
Rows matched: 2  Changed: 2  Warnings: 0
mysql> select * from fred;
+----+------------+
| id | name       |
+----+------------+
|  1 | Fred       |
|  2 | Jen        |
|  3 | Wilhelmine |
|  4 | Héloïse2   |
|  5 | Suhi2      |
+----+------------+
5 rows in set (0.00 sec)

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000008 |      357 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
mysql> show binlog events in 'mysql-bin.000008';
+------------------+-----+-------------+-----------+-------------+---------------------------------------+
| Log_name         | Pos | Event_type  | Server_id | End_log_pos | Info                                  |
+------------------+-----+-------------+-----------+-------------+---------------------------------------+
| mysql-bin.000008 |   4 | Format_desc |         1 |         120 | Server ver: 5.6.21-log, Binlog ver: 4 |
| mysql-bin.000008 | 120 | Query       |         1 |         192 | BEGIN                                 |
| mysql-bin.000008 | 192 | Table_map   |         1 |         242 | table_id: 72 (fred.fred)              |
| mysql-bin.000008 | 242 | Update_rows |         1 |         326 | table_id: 72 flags: STMT_END_F        |
| mysql-bin.000008 | 326 | Xid         |         1 |         357 | COMMIT /* xid=22 */                   |
+------------------+-----+-------------+-----------+-------------+---------------------------------------+
5 rows in set (0.00 sec)

$ sudo ./MyUndelete.py  -b /var/lib/mysql/mysql-bin.000008 -s 120 -e 357 -u

*** WARNING *** USE WITH CARE ****

Binlog file is  /var/lib/mysql/mysql-bin.000008
Start Position file is  120
End Postision file is  357
Event type ('\x1f') is an update v2
We got an update!!
Ready to revert the statement ? [y/n]
y
Sending to mysql...
Done... I hope it worked ;)

mysql> select * from fred;
+----+------------+
| id | name       |
+----+------------+
|  1 | Fred       |
|  2 | Jen        |
|  3 | Wilhelmine |
|  4 | Héloïse    |
|  5 | Suhi       |
+----+------------+
5 rows in set (0.00 sec)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

歇歇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值