10分钟搞定 MySQL 通过Binlog 数据备份和恢复

一、 首先安装MySQL

为了简便操作,我使用docker进行演示,docker安装mysql的命令如下所示:

复制代码
docker run -d \
  --name mysql \
  -p 3306:3306 \
  -e TZ=Asia/Shanghai \
  -e MYSQL_ROOT_PASSWORD=1234 \
  -v ./mysql/data:/var/lib/mysql \
  -v ./mysql/conf:/etc/mysql/conf.d \
  -v ./mysql/init:/docker-entrypoint-initdb.d \
  mysql:8.0
  • 数据持久化:-v ./mysql/data:/var/lib/mysql 让数据安全地留在了宿主机。
  • 配置文件分离:-v ./mysql/conf:/etc/mysql/conf.d 让你可以随意改配置而不用进容器。
  • 初始化脚本:-v ./mysql/init:/docker-entrypoint-initdb.d ,你可以把 .sql 建表脚本放这里,容器首次启动会自动执行。

二、Binlog介绍

Binlog (Binary Log) 就是 MySQL 的"录像机"。

它记录了数据库里所有的修改操作(比如增删改),按时间顺序排列。这就好比你把游戏里所有改变数据的操作都录了下来,存成了一部连续的电影。

对你做游戏来说,Binlog 有两个特别实用的用途:

(1)数据的"后悔药"与"时间机器"

开发过程中难免会有误操作,比如不小心执行了一条 SQL 删了测试服的用户数据。

没用 Binlog:数据可能就真没了,或者只能从昨天凌晨的备份恢复(意味着今天的测试白干了)。

有了 Binlog:你可以拿着"录像"快进到出问题的时间点,或者重放这几分钟的记录,把数据精确恢复到误操作前一秒。

(2)做"数据同步"的基石

最常见的需求。比如:

你有一个主库(负责处理用户的账号、库存、写入数据)。

你有一个从库(专门负责给官网提供排行榜查询、或者给后台客服查询数据)。

为了让从库的数据和主库一模一样,MySQL 就是利用 Binlog 把主库的"录像"同步给从库,让从库照着做一遍。

新手建议:

刚开始做项目时,如果你不会手写脚本来解析 Binlog,但一定要确保你的云数据库(比如阿里云 RDS 或腾讯云 MySQL)开启了 Binlog 功能,并且设置了合理的保留时间(比如保留 7 天)。这样即使出问题,运维人员也能帮你把数据救回来。

三、开启Binlog(数据备份)

3.1 查找mysql文件

首先,找到mysql的配置文件,如果忘了放哪了,直接让 Linux 帮你找,直接全局搜索(最暴力,推荐)

复制代码
find / -name "mysql" -type d 2>/dev/null

这条命令会从根目录开始找名字叫 mysql 的文件夹。

如果看到路径像 /root/mysql、/home/user/mysql 这样的,大概率就是它了。

(注意:它会搜到系统自带的 /var/lib/mysql,那个是系统的,不是你的,别搞混了,找带自定义路径特征的)

找到正确的路径后(比如是在 /root/mysql),以后的操作都要带上这个绝对路径

进入目录

复制代码
    cd /root/mysql   # 换成你 find 出来的真实路径

检查一下目录结构(确认无误)

你应该能看到 data、conf、init 这三个文件夹。

复制代码
ls -l

查看数据目录

复制代码
ls -l ./data/

3.2 开启binlog

查看配置目录

复制代码
ls -l ./conf

没问题!这很正常,说明你的 conf 文件夹目前是空的。

现在我们就在这个空文件夹里创建配置文件。请保持在 /root/mysql 目录下,直接复制并执行下面这段命令:

复制代码
cat > ./conf/my.cnf << EOF
[mysqld]
# 开启 Binlog
log-bin=mysql-bin
# 服务器 ID (随便设个唯一数字)
server-id=1
# 设置 Binlog 格式为 ROW (恢复数据最推荐)
binlog_format=ROW
# 日志保留 7 天,自动清理防止占满磁盘
expire_logs_days=7
# --- 核心配置:中文支持 ---
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
EOF

执行完这一步后,再检查一下:

复制代码
ls -l ./conf

3.3 重启生效

重启容器让配置生效:

复制代码
docker restart mysql

等容器重启完,你的 Binlog 功能就已经启动了!随后你可以在 ./data 目录里看到对应的日志文件生成。

四、通过Binlog实现数据恢复

4.1 数据恢复前准备,故意制造数据丢失

为了演示,我需要创建一张数据库表

我们就以 test_db 数据库和 tb_user 表为例。这是一个非常标准的实战演练

登录 MySQL

复制代码
docker exec -it mysql mysql -uroot -p1234

建库建表并插入初始数据

复制代码
CREATE DATABASE test_db;
USE test_db;

-- 创建用户表
CREATE TABLE tb_user (
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
    username VARCHAR(50) COMMENT '用户名',
    role VARCHAR(50) COMMENT '角色'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';

-- 插入两个初始用户
INSERT INTO tb_user (username, role) VALUES ('张三', '程序员');
INSERT INTO tb_user (username, role) VALUES ('李四', '医生');

-- 查看当前数据
SELECT * FROM tb_user;

此时应该有两行数据。

模拟误操作(删表)

复制代码
-- 灾难发生:误删了用户表
DROP TABLE tb_user;

-- 确认数据已丢失
SHOW TABLES;

4.2 开始恢复数据

现在 test_db 里空空如也。接下来我们打开一个新的终端窗口(或者按 Ctrl+C 退出当前 MySQL 会话),开始在 Linux 命令行进行恢复。

查看当前的 Binlog 日志文件

复制代码
ls -lh /root/mysql/data/

有新日志生成: mysql-bin.000001刚刚生成,说明你刚才所有的删表、建表、插入数据的操作,都被忠实地记录在这个小文件里了。

文件夹 test_db:这是你刚才创建的数据库目录,里面的 .ibd 文件就是真正的数据文件。

4.3 分析日志,找到误删的"案发时间点"

我们需要用到mysqlbinlog,那么简单介绍一下mysqlbinlog

mysqlbinlog 是一个独立的工具程序,并不包含在基础的 mysql 镜像里。你现在的镜像里只有数据库服务端(mysqld)和客户端(mysql),没有解析日志的工具(mysqlbinlog)。

这就像你买了一台电视机(数据库服务),它只能放电视,但它没有"录像机编辑功能"(日志工具),那个得单独买。

复制代码
# 1. 安装官方源
yum install -y https://dev.mysql.com/get/mysql80-community-release-el7-11.noarch.rpm

# 2. 安装 8.0 客户端
yum install mysql-community-client -y

检查是否安装成功

复制代码
mysqlbinlog --version

查看日志(定位误删位置)

复制代码
# 直接读宿主机文件,不要进 docker
mysqlbinlog --no-defaults /root/mysql/data/binlog.000001 | tail -n 30

先确认 MySQL 的真实数据目录和 binlog 文件位置

先登录 MySQL 客户端

复制代码
docker exec -it mysql mysql -uroot -p1234

登录后执行以下 SQL,查看 binlog 文件的真实存储路径和文件列表:

复制代码
-- 查看 binlog 文件列表(能看到的才是真实存在的)
show binary logs;

-- 查看binlog配置
SHOW VARIABLES LIKE 'log_bin%';
SHOW VARIABLES LIKE 'binlog_format%';

-- 查看 MySQL 的数据目录(binlog 默认存在这个目录下)
show variables like 'datadir';

4.4 恢复数据

因为我当前在mysql目录中,所以我使用相对路径./data/mysql-bin.000001指定该日志文件哦!

查看日志文件

复制代码
mysqlbinlog -v ./data/mysql-bin.000001

4.4.1 指定位置点恢复

有两个参数填写,一个是开始位置点,一个是结束位置点。如上图的at就是点位

复制代码
# at 1008     ← 第一个事务开始
# at 1086     ← BEGIN
# at 1151     ← INSERT操作
# at 1193     ← INSERT结束
# at 1224     ← COMMIT完成
# at 1301     ← DROP TABLE开始

DELETE/DROP语句在位置 1301

有用的数据在位置 1008-1224

复制代码
# 指定位置点
mysqlbinlog --start-position=107 \
            --stop-position=1000 \
            ./data/mysql-bin.000001 --skip-gtids | docker exec -i mysql mysql -uroot -p1234

如果只恢复单个操作

复制代码
# 提取第一个完整事务(1008到1224之间的INSERT操作)
mysqlbinlog --start-position=1008 \
            --stop-position=1224 \
            ./data/mysql-bin.000001 --skip-gtids | docker exec -i mysql mysql -uroot -p1234

提取到DROP之前的所有内容

复制代码
# 提取从开始到DROP之前的所有操作
mysqlbinlog --start-position=154 \
            --stop-position=1301 \
            ./data/mysql-bin.000001 --skip-gtids | docker exec -i mysql mysql -uroot -p1234

提取到DROP之前的所有内容

复制代码
# 提取整个文件,但跳过DROP语句
mysqlbinlog --start-position=154 \
            --stop-position=1300 \
            ./data/mysql-bin.000001 --skip-gtids | docker exec -i mysql mysql -uroot -p1234

4.4.2 指定时间区域恢复

有两个参数填写,一个是开始时间,一个是结束时间。如果有备份的话,最好回复数据可以填写最后一次备份的结束时间。

复制代码
#提取删除前的所有操作(从表创建到删除)
mysqlbinlog --start-datetime="2026-01-14 14:00:00" \
            --stop-datetime="2026-01-14 14:19:55" \
            ./data/mysql-bin.000001 --skip-gtids | docker exec -i mysql mysql -uroot -p1234

执行命令后可以发现我们的数据库恢复咯!

相关推荐
老邓计算机毕设2 小时前
SSM心理健康系统84459(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm 框架·心理健康系统·在线咨询
+VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue小型房屋租赁系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
win x2 小时前
Redis 分布式锁
数据库·redis·分布式
2501_944521002 小时前
rn_for_openharmony商城项目app实战-商品评价实现
javascript·数据库·react native·react.js·ecmascript·harmonyos
冉冰学姐2 小时前
SSM心理健康系统59q3n(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm 框架应用·心理健康系统·心理文章
heartbeat..2 小时前
零基础学 SQL:DQL/DML/DDL/DCL 核心知识点汇总(附带连接云服务器数据库教程)
java·服务器·数据库·sql
傻啦嘿哟3 小时前
Python中的@property:优雅控制类成员访问的魔法
前端·数据库·python
岁岁种桃花儿3 小时前
MySQL 8.0 基本数据类型全面解析
数据库·mysql·数据库开发
用户427007458384 小时前
第二节:使用Mongoose连接数据库
数据库