如何通过BinLog日志恢复被删除的数据

https://blog.csdn.net/TGQlovemm/article/details/144693018

一次惨痛的经历,实习期间不小心删除了生产上的角色菜单,通过备份紧急恢复了部分数据,但是还是漏了很多,最后导致客户使用的时候权限出现了问题。对此我抽时间了解了一下关于数据库恢复的相关知识,为了以后出现这种错误之后能以最小损失的代价恢复数据。

binlog文件实际上是对于数据库的正向操作

插入数据insert,binlog中保存的也是insert语句

删除数据delete,binlog中保存的也是delete语句

由此恢复数据的两种方式:

1.找到数据的插入位置,重新执行数据的插入操作

优点:方便,不需要生成逆向操作,直接执行sql脚本重新插入数据即可,对binlog的模式没有限制,row模式,statement模式都能找到具体的数据

缺点:如果插入之后还有更新操作,插入的数据不是最新的,会有问题。如果被删除的数据比较多,插入的位置比较多,找到插入的位置比较困难。

2.找到数据被删除的位置,生成逆向操作,重新执行插入操作

优点:只要找到数据被删除的位置,即可找到所有被删除的数据,比较方便。

缺点:需要通过脚本生成逆向操作,才能将数据恢复,需要保证binlog是row模式,才能找到被删除的数据,否则,statement模式不会找到具体的数据。

通用操作:

检查是否开启了binlog:

SHOW VARIABLES LIKE 'log_bin';

ON 开启 OFF关闭

开启binlog

修改配置文件(my.cnf/my.ini)

linux下MySql的配置文件目录一般是/etc/mysql中的[mysqld]部分来开启binlog

mysqld

log-bin=mysql-bin

server-id=1

binlog模式:

SHOW VARIABLES LIKE 'binlog_format';

ROW:行模式,因为它提供了更好的数据一致性。

STATEMENT:表示使用语句模式,这种模式可能会丢失一些数据,因为它仅记录执行的sql语句

MIXED:表示混合模式,在这种模式下,mysql会根据需要自动切换模式和语句模式

配置binlog模式:

同上

mysqld

binlog_format=ROW

binlog信息查询:

查询当前使用的binlog文件

show master status; 可以找到当前正在使用的binlog文件

show master logs;可以找到所有binlog文件名

show VARIABLES LIKE 'log_bin_basename';可以找到binlog文件保存的目录位置

下面才是重点:

定位binlog中sql的位置

逆向操作得到SQL语句

·获取insert语句

1.定位binlog中sql的位置

前往binlog文件所在的目录查看所有binlog文件

bash-4.2# ls /var/lib/mysql/mysql-bin* -alh

-rw-r----- 1 mysql mysql 1.1G Sep 9 02:28 /var/lib/mysql/mysql-bin.000200

-rw-r----- 1 mysql mysql 1.1G Sep 9 02:32 /var/lib/mysql/mysql-bin.000201

-rw-r----- 1 mysql mysql 1.1G Sep 9 02:39 /var/lib/mysql/mysql-bin.000202

-rw-r----- 1 mysql mysql 1.1G Sep 9 02:45 /var/lib/mysql/mysql-bin.000203

-rw-r----- 1 mysql mysql 1.1G Sep 9 07:52 /var/lib/mysql/mysql-bin.000204

-rw-r----- 1 mysql mysql 1.1G Sep 9 12:10 /var/lib/mysql/mysql-bin.000205

-rw-r----- 1 mysql mysql 1.1G Sep 10 04:40 /var/lib/mysql/mysql-bin.000206

-rw-r----- 1 mysql mysql 1.2G Sep 10 07:00 /var/lib/mysql/mysql-bin.000207

-rw-r----- 1 mysql mysql 1.1G Sep 11 07:54 /var/lib/mysql/mysql-bin.000208

-rw-r----- 1 mysql mysql 1.1G Sep 12 03:03 /var/lib/mysql/mysql-bin.000209

-rw-r--r-- 1 root root 24M Sep 11 09:06 /var/lib/mysql/mysql-bin.000209.event.log

-rw-r----- 1 mysql mysql 1.1G Sep 12 03:30 /var/lib/mysql/mysql-bin.000210

-rw-r----- 1 mysql mysql 1.1G Sep 12 08:33 /var/lib/mysql/mysql-bin.000211

-rw-r----- 1 mysql mysql 1.1G Sep 12 08:35 /var/lib/mysql/mysql-bin.000212

-rw-r----- 1 mysql mysql 1.1G Sep 12 22:00 /var/lib/mysql/mysql-bin.000213

-rw-r----- 1 mysql mysql 1.1G Sep 13 10:26 /var/lib/mysql/mysql-bin.000214

-rw-r----- 1 mysql mysql 1.1G Sep 13 10:29 /var/lib/mysql/mysql-bin.000215

-rw-r----- 1 mysql mysql 1.1G Sep 14 01:42 /var/lib/mysql/mysql-bin.000216

-rw-r----- 1 mysql mysql 637M Sep 14 06:11 /var/lib/mysql/mysql-bin.000217

-rw-r----- 1 mysql mysql 4.1K Sep 14 01:42 /var/lib/mysql/mysql-bin.index

2.估计数据的插入时间,选取对应的文件,获取对应的binlog片段

选取对应的binlog文件进行解析成可读的sql文件

mysqlbinlog --base64-output=decode-rows -v --start-datetime="2024-09-12 11:59:00" --stop-datetime="2024-09-12 12:01:00" mysql-bin.000213 > binlog.sql

3.statement模式确认binlog的位置

at 219

#240914 17:14:26 server id 1 end_log_pos 300 CRC32 0xb8159bc1 Query thread_id=1267 exec_time=0 error_code=0

SET TIMESTAMP=1726305266/*!*/;

SET @@session.pseudo_thread_id=1267/*!*/;

SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;

SET @@session.sql_mode=1436549120/*!*/;

SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;

/*!\C latin1 *//*!*/;

SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/;

SET @@session.lc_time_names=0/*!*/;

SET @@session.collation_database=DEFAULT/*!*/;

BEGIN

/*!*/;

at 300

#240914 17:14:26 server id 1 end_log_pos 414 CRC32 0xb7e0263b Query thread_id=1267 exec_time=0 error_code=0

use `tests`/*!*/;

SET TIMESTAMP=1726305266/*!*/;

insert into person values (1, 'first')

/*!*/;

at 414

#240914 17:14:26 server id 1 end_log_pos 445 CRC32 0x9345e6ca Xid = 30535

COMMIT/*!*/;

at 445

我们可以找到insert into person values (1, 'first'), 并且分别在前后的BEGIN和COMMIT找到position。

BEGIN往前找有一个position at 219, COMMIT往后找有一个postion at 445, 这就是插入语句的实际binlog范围。

4.row模式确认binlog位置

row模式的格式和statement模式可能会有少许差别,但方法是一致的。

at 219

#240914 17:16:36 server id 1 end_log_pos 292 CRC32 0xe9082d52 Query thread_id=20 exec_time=0 error_code=0

SET TIMESTAMP=1726305396/*!*/;

SET @@session.pseudo_thread_id=20/*!*/;

SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;

SET @@session.sql_mode=1436549120/*!*/;

SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;

/*!\C latin1 *//*!*/;

SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/;

SET @@session.lc_time_names=0/*!*/;

SET @@session.collation_database=DEFAULT/*!*/;

BEGIN

/*!*/;

at 292

#240914 17:16:36 server id 1 end_log_pos 345 CRC32 0x1832ced4 Table_map: `tests`.`person` mapped to number 111

at 345

#240914 17:16:36 server id 1 end_log_pos 395 CRC32 0x32d6a21b Write_rows: table id 111 flags: STMT_END_F

INSERT INTO `tests`.`person`

SET

@1=1

@2='first'

at 395

#240914 17:16:36 server id 1 end_log_pos 426 CRC32 0x07619928 Xid = 149

COMMIT/*!*/;

at 426

我们可以找到###开头的几行,包含INSERT INTO 语句。并且分别在前后的BEGIN 和 COMMIT找到position。

BEGIN往前找有一个position at 219 ,COMMIT往后找有一个position at 426,这就是插入语句的实际binlog范围。

5.根据binlog位置解析binlog文件

mysqlbinlog --start-position=219 --stop-position=426 mysql-bin.000213 > binlog.sql

7.重新写回数据

这样

mysql -uroot -proot < binlog.sql

或者

source binlog.sql;

·获取delete语句,逆向操作

at 1574

#240914 17:16:38 server id 1 end_log_pos 1642 CRC32 0x944b1b94 Query thread_id=20 exec_time=1260 error_code=0

SET TIMESTAMP=1726305398/*!*/;

BEGIN

/*!*/;

at 1642

#240914 17:16:38 server id 1 end_log_pos 1695 CRC32 0x435282e2 Table_map: `tests`.`person` mapped to number 111

at 1695

#240914 17:16:38 server id 1 end_log_pos 1745 CRC32 0x3063bf8c Delete_rows: table id 111 flags: STMT_END_F

DELETE FROM `tests`.`person`

WHERE

@1=1

@2='first'

at 1745

#240914 17:16:38 server id 1 end_log_pos 1776 CRC32 0x086c2270 Xid = 3391

COMMIT/*!*/;

逆向操作生成sql

insert into person values (1, 'first');


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/TGQlovemm/article/details/144693018

复制代码
mysql -h 127.0.0.1 -P 5577 -u root -p tent000001 <D:\yqtj\mysql-8.0.15-winx64\inctent000001.sql --force

mysqlbinlog --no-defaults --database=tent000001   ../mysql-bin.000265 >>inctent000001.sql
相关推荐
肆仙.8 小时前
单表、多表查询练习
android·adb
小李小李快乐不已11 小时前
3.1.3 MYSQL连接池
数据库·mysql·adb
冲浪中台14 小时前
MySQL 的 JSON 路径格式
mysql·adb·json
Free飝Fly17 小时前
Android R adb remount 调用流程
android·adb·remount
测试笔记(自看)1 天前
Flask接口开发--引入mysql
mysql·adb·flask
xccoding1 天前
【FW】ADB指令分类速查清单
数据库·windows·adb
lq_ioi_pl2 天前
数据库约束、常见语句等
android·adb
luo_guibin2 天前
mysql5.7无法启动报错处理无日志
mysql·adb
SQ_yyds2 天前
数据库第二周作业
android·数据库·adb
Free飝Fly2 天前
Android adb自身调试log开关
android·adb·log