记一次MySQL数据表误操作修复
背景
同事在通过SQL直接修改数据库记录时,误更新了表中的所有数据
sql
update t_1 set prop1=1, prop2=2;
联系了数据库的同事,表示直接使用BinLog回滚风险比较大,有可能整个库的数据都会出问题。
恢复方式及前提条件
计划恢复方式
介于数据库同事的"恐吓",我们考虑根据BinLog查询出修改前的原值,进行手动恢复。
前提条件
是否开启了BinLog
sql
# 值为 ON,说明已开启
SHOW VARIABLES LIKE 'log_bin';
确认BinLog的格式为ROW
sql
# 值为 ROW,则可以日志里看到旧数据
SHOW VARIABLES LIKE 'binlog_format';
找到原数据
找到BinLog并导出为SQL日志
BinLog 文件默认在 /var/lib/mysql/目录下
sql
SHOW VARIABLES LIKE 'log_bin_basename';
bash
cd /var/lib/mysql
# 查询 mysql-bin.xxxx 文件的时间
ls -l
# 根据误操作的大概时间确定 BinLog 文件范围
# 使用 mysqlbinlog 命令将 BinLog 导出为SQL日志
mysqlbinlog --no-defaults --base64-output=DECODE-ROWS -v /var/lib/mysql/mysql-bin.00000X > temp_log.sql
# 如果 BinLog 日志很大,时间跨度很长,可以增加 --start-datetime,--stop-datetime 参数来限定时间范围
mysqlbinlog --no-defaults --base64-output=DECODE-ROWS -v \
--start-datetime="2025-12-30 15:25:00" \
--stop-datetime="2025-12-30 15:35:00" \
/var/lib/mysql/mysql-bin.00000X > temp_log.sql
解读旧数据
在 temp_log.sql 文件中查询更新语句,比如 UPDATE db1.tab1
比如在 vi 中
bash
/UPDATE \`db1\`\.\`tab1\`
注意 ### WHERE 和 ### SET 之间的部分,那是修改前的数据:
text
# at 123456
#251230 15:30:01 server id 1 end_log_pos 123567 CRC32 0x12345678 UPDATE mydb.xxx
### UPDATE mydb.xxx
### WHERE
### @1=1 // 这是修改前的主键ID
### @2='旧值A' // 这是修改前 col1 的旧值(你想要找的数据)
### @3='旧值B' // 这是修改前 col2 的旧值
### SET
### @1=1
### @2='111' // 这是修改后的新值
### @3='222'
# at 123567
@1, @2... 代表表中的第 1 列、第 2 列。
WHERE 部分记录的是更新前的快照,这就是你要找回的数据。