MySQL的二进制日志(binlog)使用分析(4)——利用binlog日志恢复数据

    技术2025-05-23  41

    MySQL的二进制日志(binlog)使用分析(4)——利用binlog日志恢复数据

    利用binlog日志恢复数据,就是让mysql将保存在binlog日志中指定段落区间的SQL语句重新执行一次而已。

    下面通过一个例子说明怎样例如binlog日志恢复数据:

    一、数据库信息

    1、数据库:hist,wanggx

    mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | hist | | mysql | | performance_schema | | sys | | wanggx | +--------------------+ 6 rows in set (0.01 sec)

    2、hist数据库包含的表

    mysql> use hist; Database changed mysql> show tables; +----------------+ | Tables_in_hist | +----------------+ | course | | dept | | score | | stu | +----------------+ 4 rows in set (0.00 sec)

    3、wanggx数据库包含的表

    mysql> use wanggx; Database changed mysql> show tables; +------------------+ | Tables_in_wanggx | +------------------+ | department | | emp | +------------------+ 2 rows in set (0.00 sec)

    二、备份策略

    在每天凌晨四点对hist和wanggx数据库进行一次完全备份,命令如下:

    mysqldump -uroot -p123456 --databases -F -R -x --master-data=2 hist wanggx | gzip >/data_bak/db_bak_$(date +%F).sql.gz

    参数说明:

    (1)–databases(-B):指定要备份的数据库名称; (2)-F:刷新日志; (3)-R:备份存储过程等; (4)-x:锁表; (5)–master-data:在备份语句里添加CHANGE MASTER语句以及binlog文件及位置点信息。

    在全备份的时候使用-F选项,当数据备份操作开始时,系统就会自动刷新log,会自动产生一个新的binlog日志,这个新的binlog日志用来记录备份之后对数据库的【增、删、改】操作。

    查看备份结果:

    [root@Mysql11 data_bak]# mysqldump -uroot -p123456 --databases -F -R -x --master-data=2 hist wanggx | gzip >/data_bak/db_bak_$(date +%F).sql.gz mysqldump: [Warning] Using a password on the command line interface can be insecure. [root@Mysql11 data_bak]# ls /data_bak/ db_bak_2020-07-04.sql.gz

    查看备份结束后的日志信息:

    mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000012 | 154 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec)

    说明:从日志文件mysql-bin.000012开始记录上次备份之后对数据库的所有修改操作信息。

    由于备份时使用了【–master-data】选项,在备份语句里添加CHANGE MASTER语句以及binlog文件及位置点信息。

    [root@Mysql11 data_bak]# cat db_bak_2020-07-04.sql -- MySQL dump 10.13 Distrib 5.7.27, for Linux (x86_64) -- ............... -- -- Position to start replication or point-in-time recovery from -- #### CHANGE MASTER语句、binlog文件及位置点信息 -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000012', MASTER_LOG_POS=154; -- -- Current Database: `hist` -- ...........

    三、备份之后修改数据

    1、修改hist数据库中的stu表的数据

    (1)上次数据备份之后,hist数据库中的stu表数据如下:

    mysql> use hist; Database changed mysql> select * from stu; +----+----------+------+-----------+-------------+---------+ | id | name | age | address | phone | dept_id | +----+----------+------+-----------+-------------+---------+ | 1 | zhangsan | 21 | Xinxiang | 15578941258 | 1 | | 2 | tom | 20 | Xinxiang | 13778942222 | 1 | | 3 | jack | 21 | Zhengzhou | 13675871454 | 1 | | 4 | john | 22 | Zhengzhou | 13937681111 | 2 | | 5 | mark | 22 | Aanyang | 13055882233 | 2 | +----+----------+------+-----------+-------------+---------+ 5 rows in set (0.01 sec)

    (2)对hist数据库中的stu表进行如下操作:

    mysql> insert into stu(name,age,address,phone,dept_id) values('Obama',18,'America','13988886666',3); Query OK, 1 row affected (0.01 sec) mysql> insert into stu(name,age,address,phone,dept_id) values('Trump',19,'America','13066668888',3); Query OK, 1 row affected (0.01 sec) mysql> update stu set age=age+1 where dept_id=2; Query OK, 2 rows affected (0.00 sec) Rows matched: 2 Changed: 2 Warnings: 0 mysql> delete from stu where id=1; Query OK, 1 row affected (0.01 sec)

    (3)修改之后的数据如下:

    mysql> select * from stu; +----+-------+------+-----------+-------------+---------+ | id | name | age | address | phone | dept_id | +----+-------+------+-----------+-------------+---------+ | 2 | tom | 20 | Xinxiang | 13778942222 | 1 | | 3 | jack | 21 | Zhengzhou | 13675871454 | 1 | | 4 | john | 23 | Zhengzhou | 13937681111 | 2 | | 5 | mark | 23 | Aanyang | 13055882233 | 2 | | 6 | Obama | 18 | America | 13988886666 | 3 | | 7 | Trump | 19 | America | 13066668888 | 3 | +----+-------+------+-----------+-------------+---------+ 6 rows in set (0.00 sec)

    2、修改wanggx数据库中的department表的数据

    (1)上次数据备份之后,wanggx数据库中的department表数据如下:

    mysql> use wanggx Database changed mysql> select * from department; +---------+----------+ | dept_id | name | +---------+----------+ | 1 | guanli | | 2 | jingji | | 3 | jidian | | 4 | jisuanji | +---------+----------+ 4 rows in set (0.01 sec)

    (2)对wanggx数据库中的department表进行如下修改:

    mysql> insert into department(name) values('huagong'); Query OK, 1 row affected (0.00 sec) mysql> insert into department(name) values('yishu'); Query OK, 1 row affected (0.03 sec)

    (3)修改后的数据如下:

    mysql> select * from department; +---------+----------+ | dept_id | name | +---------+----------+ | 1 | guanli | | 2 | jingji | | 3 | jidian | | 4 | jisuanji | | 5 | huagong | | 6 | yishu | +---------+----------+ 6 rows in set (0.01 sec)

    四、模拟误操作

    由于业务部熟练或者不小心执行了如下操作:

    1、删除hist库

    mysql> drop database hist; Query OK, 4 rows affected (0.05 sec)

    2、创建hist库和t1表,并插入数据

    mysql> create database hist; Query OK, 1 row affected (0.01 sec) mysql> use hist; Database changed mysql> create table t1(id int primary key,name char(20)); Query OK, 0 rows affected (0.02 sec) mysql> insert into t1 values(1,'a'); Query OK, 1 row affected (0.00 sec) mysql> insert into t1 values(2,'b'); Query OK, 1 row affected (0.02 sec)

    五、把数据库恢复删除hist数据库之前的状态

    1、查看上次备份之后的binlog日志文件名称以及位置点信息

    [root@Mysql11 data_bak]# cat db_bak_2020-07-04.sql -- MySQL dump 10.13 Distrib 5.7.27, for Linux (x86_64) -- ............... -- -- Position to start replication or point-in-time recovery from -- #### CHANGE MASTER语句、binlog文件及位置点信息 -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000012', MASTER_LOG_POS=154; -- -- Current Database: `hist` -- ...........

    查询结果为:日志文件为【mysql-bin.000012】,位置点为【154】。

    2、备份binlog文件【mysql-bin.000012】及以后的binlog文件

    (1)查看binlog日志文件的信息

    mysql> show master logs; +------------------+-----------+ | Log_name | File_size | +------------------+-----------+ | mysql-bin.000001 | 923 | | mysql-bin.000002 | 703 | | mysql-bin.000003 | 201 | | mysql-bin.000004 | 542 | | mysql-bin.000005 | 518 | | mysql-bin.000006 | 201 | | mysql-bin.000007 | 448 | | mysql-bin.000008 | 201 | | mysql-bin.000009 | 1595 | | mysql-bin.000010 | 201 | | mysql-bin.000011 | 201 | | mysql-bin.000012 | 3456 | +------------------+-----------+ 12 rows in set (0.00 sec)

    (2)发现只需要备份【mysql-bin.000012】一个文件即可

    [root@Mysql11 data_bak]# cp /var/lib/mysql/mysql-bin.000012 /data_bak/ [root@Mysql11 data_bak]# ls /data_bak/ db_bak_2020-07-04.sql mysql-bin.000012

    3、刷新日志索引操作,重新开始新的binlog日志文件

    为了便于我们分析原因,以后所有数据库操作都会写入到下一个日志文件。

    mysql> flush logs; Query OK, 0 rows affected (0.01 sec) mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000013 | 154 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec)

    4、查看binlog日志,找到删除hist数据库的位置

    查看binlog日志文件的信息

    mysql> show binlog events in '/var/lib/mysql/mysql-bin.000012'; +------------------+------+----------------+-----------+-------------+------------------------------------------------------------------------------------------------+ | Log_name | Pos | Event_type | Server_id | End_log_pos | Info | +------------------+------+----------------+-----------+-------------+------------------------------------------------------------------------------------------------+ | mysql-bin.000012 | 4 | Format_desc | 1 | 123 | Server ver: 5.7.27-log, Binlog ver: 4 | | mysql-bin.000012 | 123 | Previous_gtids | 1 | 154 | | | mysql-bin.000012 | 154 | Anonymous_Gtid | 1 | 219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-bin.000012 | 219 | Query | 1 | 291 | BEGIN | | mysql-bin.000012 | 291 | Rows_query | 1 | 407 | # insert into stu(name,age,address,phone,dept_id) values('Obama',18,'America','13988886666',3) | | mysql-bin.000012 | 407 | Table_map | 1 | 464 | table_id: 136 (hist.stu) | | mysql-bin.000012 | 464 | Write_rows | 1 | 538 | table_id: 136 flags: STMT_END_F | | mysql-bin.000012 | 538 | Xid | 1 | 569 | COMMIT /* xid=405 */ | | mysql-bin.000012 | 569 | Anonymous_Gtid | 1 | 634 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-bin.000012 | 634 | Query | 1 | 706 | BEGIN | | mysql-bin.000012 | 706 | Rows_query | 1 | 822 | # insert into stu(name,age,address,phone,dept_id) values('Trump',19,'America','13066668888',3) | | mysql-bin.000012 | 822 | Table_map | 1 | 879 | table_id: 136 (hist.stu) | | mysql-bin.000012 | 879 | Write_rows | 1 | 953 | table_id: 136 flags: STMT_END_F | | mysql-bin.000012 | 953 | Xid | 1 | 984 | COMMIT /* xid=406 */ | | mysql-bin.000012 | 984 | Anonymous_Gtid | 1 | 1049 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-bin.000012 | 1049 | Query | 1 | 1121 | BEGIN | | mysql-bin.000012 | 1121 | Rows_query | 1 | 1185 | # update stu set age=age+1 where dept_id=2 | | mysql-bin.000012 | 1185 | Table_map | 1 | 1242 | table_id: 136 (hist.stu) | | mysql-bin.000012 | 1242 | Update_rows | 1 | 1298 | table_id: 136 flags: STMT_END_F | | mysql-bin.000012 | 1298 | Xid | 1 | 1329 | COMMIT /* xid=407 */ | | mysql-bin.000012 | 1329 | Anonymous_Gtid | 1 | 1394 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-bin.000012 | 1394 | Query | 1 | 1466 | BEGIN | | mysql-bin.000012 | 1466 | Rows_query | 1 | 1516 | # delete from stu where id=1 | | mysql-bin.000012 | 1516 | Table_map | 1 | 1573 | table_id: 136 (hist.stu) | | mysql-bin.000012 | 1573 | Delete_rows | 1 | 1613 | table_id: 136 flags: STMT_END_F | | mysql-bin.000012 | 1613 | Xid | 1 | 1644 | COMMIT /* xid=408 */ | | mysql-bin.000012 | 1644 | Anonymous_Gtid | 1 | 1709 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-bin.000012 | 1709 | Query | 1 | 1783 | BEGIN | | mysql-bin.000012 | 1783 | Rows_query | 1 | 1853 | # insert into department(name) values('huagong') | | mysql-bin.000012 | 1853 | Table_map | 1 | 1911 | table_id: 137 (wanggx.department) | | mysql-bin.000012 | 1911 | Write_rows | 1 | 1959 | table_id: 137 flags: STMT_END_F | | mysql-bin.000012 | 1959 | Xid | 1 | 1990 | COMMIT /* xid=422 */ | | mysql-bin.000012 | 1990 | Anonymous_Gtid | 1 | 2055 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-bin.000012 | 2055 | Query | 1 | 2129 | BEGIN | | mysql-bin.000012 | 2129 | Rows_query | 1 | 2197 | # insert into department(name) values('yishu') | | mysql-bin.000012 | 2197 | Table_map | 1 | 2255 | table_id: 137 (wanggx.department) | | mysql-bin.000012 | 2255 | Write_rows | 1 | 2301 | table_id: 137 flags: STMT_END_F | | mysql-bin.000012 | 2301 | Xid | 1 | 2332 | COMMIT /* xid=423 */ | | mysql-bin.000012 | 2332 | Anonymous_Gtid | 1 | 2397 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | ############## 删除hist数据库的位置2397################################################# | mysql-bin.000012 | 2397 | Query | 1 | 2489 | drop database hist | ####################################################################################### | mysql-bin.000012 | 2489 | Anonymous_Gtid | 1 | 2554 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-bin.000012 | 2554 | Query | 1 | 2648 | create database hist | | mysql-bin.000012 | 2648 | Anonymous_Gtid | 1 | 2713 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-bin.000012 | 2713 | Query | 1 | 2836 | use `hist`; create table t1(id int primary key,name char(20)) | | mysql-bin.000012 | 2836 | Anonymous_Gtid | 1 | 2901 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-bin.000012 | 2901 | Query | 1 | 2973 | BEGIN | | mysql-bin.000012 | 2973 | Rows_query | 1 | 3025 | # insert into t1 values(1,'a') | | mysql-bin.000012 | 3025 | Table_map | 1 | 3073 | table_id: 141 (hist.t1) | | mysql-bin.000012 | 3073 | Write_rows | 1 | 3115 | table_id: 141 flags: STMT_END_F | | mysql-bin.000012 | 3115 | Xid | 1 | 3146 | COMMIT /* xid=433 */ | | mysql-bin.000012 | 3146 | Anonymous_Gtid | 1 | 3211 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-bin.000012 | 3211 | Query | 1 | 3283 | BEGIN | | mysql-bin.000012 | 3283 | Rows_query | 1 | 3335 | # insert into t1 values(2,'b') | | mysql-bin.000012 | 3335 | Table_map | 1 | 3383 | table_id: 141 (hist.t1) | | mysql-bin.000012 | 3383 | Write_rows | 1 | 3425 | table_id: 141 flags: STMT_END_F | | mysql-bin.000012 | 3425 | Xid | 1 | 3456 | COMMIT /* xid=434 */ | | mysql-bin.000012 | 3456 | Rotate | 1 | 3503 | mysql-bin.000013;pos=4 | +------------------+------+----------------+-----------+-------------+------------------------------------------------------------------------------------------------+ 57 rows in set (0.00 sec)

    也可以使用mysqlbinlog -v来查找。

    5、先把上次全备的数据恢复

    (1)恢复数据

    [root@Mysql11 data_bak]# mysql -uroot -p123456 < /data_bak/db_bak_2020-07-04.sql mysql: [Warning] Using a password on the command line interface can be insecure.

    (2)查看数据

    mysql> use hist; Database changed mysql> select * from stu; +----+----------+------+-----------+-------------+---------+ | id | name | age | address | phone | dept_id | +----+----------+------+-----------+-------------+---------+ | 1 | zhangsan | 21 | Xinxiang | 15578941258 | 1 | | 2 | tom | 20 | Xinxiang | 13778942222 | 1 | | 3 | jack | 21 | Zhengzhou | 13675871454 | 1 | | 4 | john | 22 | Zhengzhou | 13937681111 | 2 | | 5 | mark | 22 | Aanyang | 13055882233 | 2 | +----+----------+------+-----------+-------------+---------+ 5 rows in set (0.00 sec) mysql> use wanggx; Database changed mysql> show tables; +------------------+ | Tables_in_wanggx | +------------------+ | department | | emp | +------------------+ 2 rows in set (0.00 sec) mysql> select * from department; +---------+----------+ | dept_id | name | +---------+----------+ | 1 | guanli | | 2 | jingji | | 3 | jidian | | 4 | jisuanji | +---------+----------+ 4 rows in set (0.00 sec)

    6、恢复上次全备之后对数据进行的修改

    (1)恢复删除hist数据库之前的操作

    [root@Mysql11 data_bak]# mysqlbinlog --stop-position=2397 /var/lib/mysql/mysql-bin.000012 > /data_bak/hist_before.sql [root@Mysql11 data_bak]# [root@Mysql11 data_bak]# mysql -uroot -p123456 -e "source /data_bak/hist_before.sql" mysql: [Warning] Using a password on the command line interface can be insecure.

    查看数据:

    mysql> use hist; Database changed mysql> select * from stu; +----+-------+------+-----------+-------------+---------+ | id | name | age | address | phone | dept_id | +----+-------+------+-----------+-------------+---------+ | 2 | tom | 20 | Xinxiang | 13778942222 | 1 | | 3 | jack | 21 | Zhengzhou | 13675871454 | 1 | | 4 | john | 23 | Zhengzhou | 13937681111 | 2 | | 5 | mark | 23 | Aanyang | 13055882233 | 2 | | 6 | Obama | 18 | America | 13988886666 | 3 | | 7 | Trump | 19 | America | 13066668888 | 3 | +----+-------+------+-----------+-------------+---------+ 6 rows in set (0.00 sec) mysql> use wanggx Database changed mysql> select * from department; +---------+----------+ | dept_id | name | +---------+----------+ | 1 | guanli | | 2 | jingji | | 3 | jidian | | 4 | jisuanji | | 5 | huagong | | 6 | yishu | +---------+----------+ 6 rows in set (0.00 sec)

    (2)恢复删除hist数据库之后的操作

    [root@Mysql11 data_bak]# mysql -uroot -p123456 -e "use hist;drop table t1;" mysql: [Warning] Using a password on the command line interface can be insecure. [root@Mysql11 data_bak]# mysqlbinlog --start-position=2648 /var/lib/mysql/mysql-bin.000012 > /data_bak/hist_after.sql [root@Mysql11 data_bak]# mysql -uroot -p123456 -e "source /data_bak/hist_after.sql" mysql: [Warning] Using a password on the command line interface can be insecure.

    查看数据:

    mysql> use hist; Database changed mysql> show tables; +----------------+ | Tables_in_hist | +----------------+ | course | | dept | | score | | stu | | t1 | +----------------+ 5 rows in set (0.00 sec) mysql> select * from t1; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | +----+------+ 2 rows in set (0.00 sec)

    至此,就完成了数据库的恢复!!!

    Processed: 0.015, SQL: 9