MySQL Binlog:数据备份、恢复和同步的秘密武器

163 阅读7分钟

当你的程序碰到一些莫名其妙的bug时,比如,程序运行正常,但是数据库数据查出来却是其他数据,或者说不是符合你预期的数据,这个时候,你是不是急切的想知道数据库这条数据是怎么来的;又或者当你误删除某张表或者某个库,这个时候,我想你应该需要binlog的帮助

binlog的定义是mysql数据库中的二进制日志文件,用于记录数据库的所有更改操作。它以二进制的形式存储,包含了对数据库执行的所有修改操作的详细信息,如插入、更新、删除等。Binlog是MySQL事务日志的一部分,与Redo Log(重做日志)一起,确保数据库的一致性、持久性,以及提供一些关键的数据库管理功能。

通过定义我们可以很清晰的知道binlog日志的作用,今天,我们来讲讲如何根据binlog日志查看数据的修改操作记录以及恢复数据。

这里,先申明下,测试环境为window下,为了方便,首先,第一步,需要确认是否开启了binlog日志,可以使用下面的命令查看当前数据库是否开启binlog

-- 查看是否开启binlog日志
SHOW VARIABLES LIKE 'log_bin';

微信图片_20240728151200.png 如果是开启状态,则查出的结果显示为ON,否者为OFF,如果是OFF,则需要通过设置mysql配置文件my.cnf来开启

server_id=1 
log_bin=mysql-bin 
binlog_format=ROW

好了,以上就是查看开启日志状态以及设置开启binlog日志状态,做完这些可以开始今天的主题了

-- 查看binlog日志文件列表
show binary logs;

根据上面这个可以查看当前库的所有binlog日志文件,我机器上的日志文件长这样

image.png

-- 查看binlog日志文件地址
show variables LIKE 'datadir';

这个是查看你的binlog日志位于哪个路径下,这个我们后面会用的到的

-- 查看某个binlog日志文件事件
show binlog events in 'binlog.000706';

这个是查看某一个binlog日志文件的事件信息

微信图片_20240728151751.png 像这样的信息,其实这些信息对我们来说有用的可能就只有Table_map了,可以看到当前记录的是哪张表的修改信息

接下来是重头戏

mysqlbinlog --no-defaults --base64-output=decode-rows -vv --start-datetime="2024-07-28 10:20:00" --stop-datetime="2024-07-28 11:40:00" ../data/binlog.000706 > test.txt

这个命令是把binlog.000706日志文件的内容打印到test.txt文件中,这个生成的文件路劲是你本机安装的mysql的bin目录下,稍微解释一下这个命令吧

mysqlbinlog:这个是mysql的bin目录下的一个exe文件,可以用来阅读和转储 MySQL Binlog 的内容

--no-defaults:这个命令的作用是告诉 mysqlbinlog 不要加载默认的配置文件

--base64-output=decode-row:这个命令的作用是告诉 mysqlbinlog 当输出 Binlog 内容时,使用 Base64 编码,然后在每一行末尾追加一个回车符(换行符)。

-v或者-vv: 是用于控制输出详细程度的,其中-vv-v更详细,多了数据库表中字段的长度和类型的注释

--start-datetime="2024-07-28 10:20:00":这个就是指定从这个时间点开始查询binlog日志文件,其中,在windows中,这里必须使用双引号,不知道在linux下是否单引号可行,有空可以去实践一下,之前我在看网上一些文章时大多用的都是单引号,为此我还掉在这个坑里很久

--stop-datetime="2024-07-28 11:40:00":这个和start一样,只不过指定的结束时间

../data/binlog.000706:这个是我们binlog日志文件的路径,这里使用的是相对路径,因为我是在mysql的bin目录下执行的该命令,如果你的bin路劲已经添加到了path中,可以把这个替换为绝对路径

> test.txt:这个就是我们需要查看的binlog日志文件打印的内容了,这里默认生成在你当前执行该命令的路径下,同样你也可以指定绝对路径了

好了,命令解析完成了,执行看看结果吧

### INSERT INTO `gorm`.`user_basics`
### SET
###   @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=NULL /* DATETIME(3) meta=3 nullable=1 is_null=1 */
###   @3=NULL /* DATETIME(3) meta=3 nullable=1 is_null=1 */
###   @4=NULL /* DATETIME(3) meta=3 nullable=1 is_null=1 */
###   @5='222' /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=0 */
###   @6='2222' /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=0 */
###   @7='222' /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=0 */
###   @8='22' /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=0 */
###   @9='222' /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=0 */
###   @10='222' /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=0 */
###   @11='222' /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=0 */
###   @12=NULL /* DATETIME(3) meta=3 nullable=1 is_null=1 */
###   @13=NULL /* DATETIME(3) meta=3 nullable=1 is_null=1 */
###   @14=NULL /* DATETIME(3) meta=3 nullable=1 is_null=1 */
###   @15=NULL /* TINYINT meta=0 nullable=1 is_null=1 */
###   @16=NULL /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=1 */
# at 498
#240728 10:28:42 server id 1  end_log_pos 529 CRC32 0x543c6b86 	Xid = 70
COMMIT/*!*/;
# at 529
#240728 10:29:01 server id 1  end_log_pos 608 CRC32 0x3c0a4d6c 	Anonymous_GTID	last_committed=1	sequence_number=2	rbr_only=yes	original_committed_timestamp=1722133741349839	immediate_commit_timestamp=1722133741349839	transaction_length=371
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
# original_commit_timestamp=1722133741349839 (2024-07-28 10:29:01.349839 中国标准时间)
# immediate_commit_timestamp=1722133741349839 (2024-07-28 10:29:01.349839 中国标准时间)
/*!80001 SET @@session.original_commit_timestamp=1722133741349839*//*!*/;
/*!80014 SET @@session.original_server_version=80029*//*!*/;
/*!80014 SET @@session.immediate_server_version=80029*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 608
#240728 10:29:01 server id 1  end_log_pos 683 CRC32 0xfe3d8665 	Query	thread_id=11	exec_time=0	error_code=0
SET TIMESTAMP=1722133741/*!*/;

上面这些是执行参数 -vv的查询结果,可以看到详细的记录了新增语句的记录,这里只是测试了下新增的数据,修改和删除的数据也是一样的,也可以测试下


#240728 15:44:42 server id 1  end_log_pos 1240 CRC32 0xe51bf86c 	Delete_rows: table id 95 flags: STMT_END_F
### DELETE FROM `gorm`.`user_basics`
### WHERE
###   @1=3 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=NULL /* DATETIME(3) meta=3 nullable=1 is_null=1 */
###   @3=NULL /* DATETIME(3) meta=3 nullable=1 is_null=1 */
###   @4=NULL /* DATETIME(3) meta=3 nullable=1 is_null=1 */
###   @5='444' /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=0 */
###   @6='2224442' /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=0 */
###   @7='44' /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=0 */
###   @8='44' /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=0 */
###   @9='44' /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=0 */
###   @10='44' /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=0 */
###   @11='44' /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=0 */
###   @12=NULL /* DATETIME(3) meta=3 nullable=1 is_null=1 */
###   @13=NULL /* DATETIME(3) meta=3 nullable=1 is_null=1 */
###   @14=NULL /* DATETIME(3) meta=3 nullable=1 is_null=1 */
###   @15=NULL /* TINYINT meta=0 nullable=1 is_null=1 */
###   @16=NULL /* LONGBLOB/LONGTEXT meta=4 nullable=1 is_null=1 */
# at 1240
#240728 15:44:42 server id 1  end_log_pos 1271 CRC32 0xa6108875 	Xid = 303

这里可以看到我们删除的这条数据

以上就是我们所有的内容了

最后,还是要送上一位名人曾说的一句话:手上没有剑和有剑不用是两回事!