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

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

相关推荐
Exquisite.40 分钟前
企业高性能web服务器(4)
运维·服务器·前端·网络·mysql
知识分享小能手1 小时前
SQL Server 2019入门学习教程,从入门到精通,SQL Server 2019数据库的操作(2)
数据库·学习·sqlserver
踩坑小念2 小时前
秒杀场景下如何处理redis扣除状态不一致问题
数据库·redis·分布式·缓存·秒杀
萧曵 丶2 小时前
MySQL 语句书写顺序与执行顺序对比速记表
数据库·mysql
Wiktok3 小时前
MySQL的常用数据类型
数据库·mysql
曹牧3 小时前
Oracle 表闪回(Flashback Table)
数据库·oracle
J_liaty4 小时前
Redis 超详细入门教程:从零基础到实战精通
数据库·redis·缓存
m0_706653234 小时前
用Python批量处理Excel和CSV文件
jvm·数据库·python
山岚的运维笔记4 小时前
SQL Server笔记 -- 第15章:INSERT INTO
java·数据库·笔记·sql·microsoft·sqlserver
夹锌饼干5 小时前
mysql死锁排查流程--(处理mysql阻塞问题)
java·mysql