如何通过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
相关推荐
夜雪一千13 小时前
MySQL 全局锁是什么?原理、风险、备份踩坑完整实战
android·mysql·adb
clorinda20 小时前
MySQL 入门笔记:DQL 基础查询与常用函数
adb
Code额21 小时前
基于 SQLAlchemy 2.x,面向 MySQL 数据库的从入门到精通实战教程(2)
数据库·sql·mysql·adb·ai
游戏开发爱好者82 天前
WebSocket 抓包怎么查看内容?从握手到消息帧完整解读
网络协议·计算机网络·网络安全·ios·adb·https·udp
00后程序员张3 天前
SSL Pinning 抓包抓不到明文?绕过证书固定的几种方案
网络协议·计算机网络·网络安全·ios·adb·https·udp
没文化的阿浩4 天前
【MySQL】数据类型
android·mysql·adb
黄毛火烧雪下4 天前
智能眼镜无线adb调试
adb
游戏开发爱好者84 天前
带签名时间戳接口的重放与压力测试实战,用动态值在发送前现算签名
网络协议·计算机网络·网络安全·ios·adb·https·压力测试
Lethehong7 天前
MySQL迁移如何做到零改造?四层兼容方案详解
数据库·mysql·adb
陈卿诺语9 天前
MySQL错误-this is incompatible with sql_mode=only_full_group_by完美解决方案
sql·mysql·adb