依据binlog恢复数据

参考资料地址1: 解析MySQL binlog

一、binlog简介

binlog即binary log,二进制日志文件。它记录了数据库所有执行的DDL和DML语句(除了数据查询语句select、show等),以事件形式记录并保存在二进制文件中。

binlog主要有两个应用场景

一是用于复制,master把它的二进制日志传递给slaves来达到master-slave数据一致的目的。

二是用于数据恢复,例如还原备份后,可以重新执行备份后新产生的binlog,使得数据库保持最新状态。

binlog日志可以选择三种模式,分别是 STATEMENT、 ROW、 MIXED,下面简单介绍下这三种模式:

  • STATEMENT:基于SQL语句的复制,每一条会修改数据的sql语句会记录到binlog中。该模式下产生的binlog日志量会比较少,但可能导致主从数据不一致。
  • ROW:基于行的复制,不记录每一条具体执行的SQL语句,仅需记录哪条数据被修改了,以及修改前后的样子。该模式下产生的binlog日志量会比较大,但优点是会非常清楚的记录下每一行数据修改的细节,主从复制不会出错。
  • Mixed:混合模式复制,以上两种模式的混合使用,一般的复制使用STATEMENT模式保存binlog,对于STATEMENT模式无法复制的操作使用ROW模式保存binlog,MySQL会根据执行的SQL语句选择日志保存方式。
  • binlog模式在MySQL 5.7.7之前,默认为 STATEMENT,在之后的版本中,默认为ROW。这里建议采用ROW模式,因为ROW模式更安全,可以清楚记录每行数据修改的细节。

二 、binlog相关参数

binlog默认情况下是不开启的,不过一般情况下初始化的时候建议在配置文件中增加log-bin参数来开启binlog。

log-bin

配置文件中增加log-bin配置

[mysqld]
log-bin = binlog

不指定路径默认在data目录下,也可以指定路径

[mysqld]
log-bin = /data/mysql/logs/binlog

查看数据库是否开启了binlog

show variables like ‘log_bin%’;
开启binlog后,还需注意一些与binlog相关的参数,下面简单介绍下相关参数:

binlog_format

设置binlog模式,建议设为ROW。

binlog_do_db

此参数表示只记录指定数据库的二进制日志,默认全部记录,一般情况下不建议更改。

binlog_ignore_db

此参数表示不记录指定的数据库的二进制日志,同上,一般不显式指定。

expire_logs_days

此参数控制二进制日志文件保留天数,默认值为0,表示不自动删除,可设置为0~99。可根据实际情况设置,比如保留15天或30天。MySQL8.0版本可用binlog_expire_logs_seconds参数代替。

max_binlog_size

控制单个二进制日志大小,当前日志文件大小超过此变量时,执行切换动作。此参数的最大和默认值是1GB,该设置并不能严格控制Binlog的大小,尤其是Binlog比较靠近最大值而又遇到一个比较大事务时,为了保证事务的完整性,不可能做切换日志的动作,只能将该事务的所有SQL都记录进当前日志,直到事务结束。一般情况下可采取默认值。

log_bin_trust_function_creators

当二进制日志启用后,此参数就会启用。它控制是否可以信任存储函数创建者,不会创建写入二进制日志引起不安全事件的存储函数。如果设置为0(默认值),用户不得创建或修改存储函数,除非它们具有除CREATE ROUTINE或ALTER ROUTINE特权之外的SUPER权限。建议设置为1。

sync_binlog

控制MySQL服务端将二进制日志同步到磁盘的频率,默认值为1。
设置为0,表示MySQL不控制binlog的刷新,由文件系统自己控制它的缓存的刷新;
设置为1,表示每次事务提交,MySQL都会把binlog刷下去,这是最安全的设置,但由于磁盘写入次数增加,可能会对性能产生负面影响;
设置为n,其中n为0或1以外的值,在进行n次事务提交以后,Mysql将执行一次fsync之类的磁盘同步指令,将Binlog文件缓存刷新到磁盘。
推荐设置为1,出于性能考虑也可酌情调整。

三、恢复数据(demo)

准备一个开启binlog模式的数据库,具体操作见补充

常用命令

-- 查看bin-log是否开启
show variables like '%log_bin%';
-- 查看所有binlog日志文件列表
show master logs;
-- 刷新日志,此刻开始产生一个新编号的binlog文件
Flush logs;
-- 清空所有binlog日志命令
reset master;
-- 查看最后一个binlog日志的编号名称及其最后一个操作事件pos结束点的值:
show master status; 
-- 查看(mysql-bin.000002)binlog
show binlog events in 'mysql-bin.000002';
--查看binlog模式
show variables like 'binlog_format';
-- 指定位点查询,比如从pos为746开始查询
SHOW BINLOG EVENTS IN 'binlog.000008' FROM 746;
-- 指定位点分页查询
SHOW BINLOG EVENTS IN 'binlog.000008' FROM 746 LIMIT 0,5

创建一个test1数据库

image-20221002175502873

为排除干扰,我们先清空之前的binlog日志(只在自己的mysql测试)

-- 查看bin-log是否开启
show variables like '%log_bin%';
-- 清空所有binlog日志命令
reset master;

准备基础数据

建一个user表,并插入四条数据

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '姓名',
  `age` int(11) NOT NULL DEFAULT 1 COMMENT '年龄',
  `remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '备注',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

INSERT INTO `user` VALUES (1, '张三', 18, '');
INSERT INTO `user` VALUES (2, '李四', 19, '');
INSERT INTO `user` VALUES (3, '王五', 12, '');
INSERT INTO `user` VALUES (4, '赵四', 199, '');
-- 查看所有binlog日志文件列表
show master logs;
-- 查看(mysql-bin.000001)binlog
show binlog events in 'mysql-bin.000001';

如图

image-20221002181839864

image-20221002181824707

在之后的操作记录在新的日志文件中,并分析

-- 刷新日志,此刻开始产生一个新编号的binlog文件
Flush logs;

image-20221002182318094

image-20221002182314269

恢复删除的数据

插入这两条数据后

INSERT INTO `user` VALUES (5, '小青', 12, '');
INSERT INTO `user` VALUES (6, '小白', 19, '');

误删除这两条数据(不小心)

查看binlog日志可以看到(注意两条插入语句的pos)

show binlog events in 'mysql-bin.000002';

image-20221002183121200

查看user表确实删除了

恢复数据操作(在指定库中恢复指定位点间的操作)

进入mysql容器内部

docker exec -it de9e411314b3 /bin/bash

image-20221002183803721

恢复删除的数据

/usr/bin/mysqlbinlog  --start-position=1609 --stop-position=1822 --database=test1  /var/lib/mysql/mysql-bin.000002 | /usr/bin/mysql -uroot -p123456 -v test1

/usr/bin/mysqlbinlog 为binlog命令

--start-position=219为恢复的开始位置

--stop-position=706为恢复的结束位置

--database=test指定数据库为demo_test

/var/lib/mysql/mysql-bin.000002 为binlog日志

| /usr/bin/mysql -uroot -p123456 -v test 通过管道连接数据库,并通过-v显示详细信息

控制台无报错

image-20221002183531217

看到表数据也恢复了

image-20221002183640656

补充

运行一个开启binlog模式的mysql(docker)

1.查看当前mysql是否开启binlog模式
-- 查看bin-log是否开启
show variables like '%log_bin%';

如果log_bin的值为OFF是未开启,为ON是已开启

image-20220927213646681

2.运行一个docker挂载数据卷的mysql容器

需提前在宿主机目录下创建一个文件用于保存mysql的数据集,/mydata/mysql/data

mkdir -p /mydata/mysql/data

基于mysql:5.7镜像

docker run -d -p 3306:3306 --privileged=true --name=mysql5.7 -v /mydata/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7 \
> --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

注: --privileged=true 是为了解决权限问题,参考资料地址: https://blog.csdn.net/weixin_34370110/article/details/114166390

3.开启binlog日志
docker exec mysql5.7 bash -c "echo 'log-bin=/var/lib/mysql/mysql-bin' >> /etc/mysql/mysql.conf.d/mysqld.cnf"

docker exec mysql5.7 bash -c "echo 'server-id=123454' >> /etc/mysql/mysql.conf.d/mysqld.cnf"
4.重启mysql生效
docker restart mysql5.7
posted @ 2022-10-04 17:37  进击的小蔡鸟  阅读(3177)  评论(0编辑  收藏  举报