基于binlog恢复误删除MySQL数据

AI 提示词

复制代码
[root@appdb-01 qding]# ls
mysqld-bin.054733  mysqld-bin.054736  mysqld-bin.054739  mysqld-bin.054742  mysqld-bin.054745  relay.000101  relay.000104  relay.index
mysqld-bin.054734  mysqld-bin.054737  mysqld-bin.054740  mysqld-bin.054743  mysqld-bin.index   relay.000102  relay.000105
mysqld-bin.054735  mysqld-bin.054738  mysqld-bin.054741  mysqld-bin.054744  relay.000100       relay.000103  relay.000106
[root@appdb-01 qding]#


这是我的binlog文件, 我刚刚执行的delete语句误删除了部分数据,我想恢复我删除的数据。涉及的数据库是db_iam 数据表是 t_iam_func_auth

进入binlog目录

确认最新binlog文件‌

根据文件列表,最新的是mysqld-bin.054745(数字最大的文件)6。

解析binlog内容‌

使用mysqlbinlog工具解析,注意添加--database--base64-output参数:

shell 复制代码
mysqlbinlog --base64-output=decode-rows -v --database=db_iam mysqld-bin.054745 > parsed_binlog.sql

定位DELETE语句‌

在生成的parsed_binlog.sql中搜索以下内容:

表名t_iam_func_auth

操作类型### DELETE FROM,这是其中部分数据:

复制代码
###   @17='XZ'
###   @18='增加问卷配置人员权限'
###   @19=NULL
# at 154852463
#250610 16:50:29 server id 453309  end_log_pos 154852494 CRC32 0x70183b1f 	Xid = 635330624
COMMIT/*!*/;
# at 154852494
#250610 16:50:29 server id 453309  end_log_pos 154852559 CRC32 0x36be420c 	Anonymous_GTID	last_committed=5320	sequence_number=16105	rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 154852559
#250610 16:50:29 server id 453309  end_log_pos 154852635 CRC32 0xfd531c3d 	Query	thread_id=6117380	exec_time=0	error_code=0
SET TIMESTAMP=1749545429/*!*/;
BEGIN
/*!*/;
# at 154852635
# at 154852753
#250610 16:50:29 server id 453309  end_log_pos 154852866 CRC32 0xe6a38df5 	Table_map: `db_iam`.`t_iam_func_auth` mapped to number 56488
# at 154852866
#250610 16:50:29 server id 453309  end_log_pos 154853264 CRC32 0x448e2624 	Delete_rows: table id 56488 flags: STMT_END_F
### DELETE FROM `db_iam`.`t_iam_func_auth`
### WHERE
###   @1='00c5383a-d564-47e8-b905-7335e740ea31'
###   @2='FP.XZ.QUESTION.7858636'
###   @3='9ea88e7d-b92e-4c8b-a394-cb7fc6b93d9b'
###   @4='edd8239e-a049-4bdc-954f-41fa60c6894c'
###   @5='U'
###   @6=1
###   @7=0
###   @8='605aeca6-01a8-4172-959f-34fff0cf0e67'
###   @9=1742459189
###   @10='605aeca6-01a8-4172-959f-34fff0cf0e67'
###   @11=1743040916
###   @12='984ff0e4-68ad-4ca1-a1bf-d38d4f785ae5'
###   @13='88c514fd-7c1f-4696-8a2c-cfa49ae1e2c2'
###   @14=NULL
###   @15=NULL
###   @16='984ff0e4-68ad-4ca1-a1bf-d38d4f785ae5'
###   @17='XZ'
###   @18='系统初始化'
###   @19=NULL
# at 154853264
#250610 16:50:29 server id 453309  end_log_pos 154853295 CRC32 0x5bd6c7f8 	Xid = 635330630
COMMIT/*!*/;
# at 154853295
#250610 16:50:29 server id 453309  end_log_pos 154853360 CRC32 0x3354fd33 	Anonymous_GTID	last_committed=5320	sequence_number=16106	rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 154853360
#250610 16:50:29 server id 453309  end_log_pos 154853436 CRC32 0x64d6f71e 	Query	thread_id=6117380	exec_time=0	error_code=0
SET TIMESTAMP=1749545429/*!*/;
BEGIN
/*!*/;
# at 154853436
# at 154853554
#250610 16:50:29 server id 453309  end_log_pos 154853667 CRC32 0x1fb2c80b 	Table_map: `db_iam`.`t_iam_func_auth` mapped to number 56488
# at 154853667
#250610 16:50:29 server id 453309  end_log_pos 154854080 CRC32 0x2a7b4493 	Delete_rows: table id 56488 flags: STMT_END_F
### DELETE FROM `db_iam`.`t_iam_func_auth`
### WHERE
###   @1='027c0a0c-9c1c-4fca-ab18-4ebfdafe3ab2'
###   @2='FP.XZ.QUESTION.7858778'
###   @3='9cd3db3c-75a0-48bf-a047-9e30deb57c33'
###   @4='edd8239e-a049-4bdc-954f-41fa60c6894c'
###   @5='R'
###   @6=1
###   @7=0
###   @8='1a7a3bb3-eeb9-454e-b458-d2da75c9539f'
###   @9=1747275151
###   @10='1a7a3bb3-eeb9-454e-b458-d2da75c9539f'
###   @11=1747275343
###   @12='984ff0e4-68ad-4ca1-a1bf-d38d4f785ae5'
###   @13='88c514fd-7c1f-4696-8a2c-cfa49ae1e2c2'
###   @14=NULL
###   @15=NULL
###   @16='984ff0e4-68ad-4ca1-a1bf-d38d4f785ae5'
###   @17='XZ'
###   @18='增加问卷配置人员权限'
###   @19=NULL
# at 154854080
#250610 16:50:29 server id 453309  end_log_pos 154854111 CRC32 0x3d46f972 	Xid = 635330631
COMMIT/*!*/;
# at 154854111
#250610 16:50:29 server id 453309  end_log_pos 154854176 CRC32 0xc755be74 	Anonymous_GTID	last_committed=5320	sequence_number=16107	rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 154854176
#250610 16:50:29 server id 453309  end_log_pos 154854252 CRC32 0x103fa6aa 	Query	thread_id=6117380	exec_time=0	error_code=0
SET TIMESTAMP=1749545429/*!*/;
BEGIN
/*!*/;

通过JAVA代码还原SQL语句

java 复制代码
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class BinlogToInsertConverter {
    private static final Pattern DELETE_PATTERN = Pattern.compile(
            "### DELETE FROM `([^`]+)`\\.`([^`]+)`.*?### WHERE(.*?)(?=# at|COMMIT)",
            Pattern.DOTALL
    );
    private static final Pattern FIELD_PATTERN = Pattern.compile(
            "###\\s+@(\\d+)='?(.*?)'?(?:\\s|$|NULL)",
            Pattern.DOTALL
    );
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) {
        String filePath = "/Users/admin/Downloads/parsed_binlog.txt";
        try {
            List<String> insertStatements = convertDeleteToInsert(filePath);
            for (String insert : insertStatements) {
                System.out.println(insert+";");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static List<String> convertDeleteToInsert(String filePath) throws IOException {
        List<String> result = new ArrayList<>();
        StringBuilder fileContent = new StringBuilder();

        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                fileContent.append(line).append("\n");
            }
        }

        Matcher deleteMatcher = DELETE_PATTERN.matcher(fileContent.toString());
        while (deleteMatcher.find()) {
            String database = deleteMatcher.group(1);
            String table = deleteMatcher.group(2);
            String whereClause = deleteMatcher.group(3);

            List<String> values = new ArrayList<>();

            Matcher fieldMatcher = FIELD_PATTERN.matcher(whereClause);
            while (fieldMatcher.find()) {
                String fieldNum = fieldMatcher.group(1);
                String value = fieldMatcher.group(2);

                if ("NULL".equals(value)) {
                    values.add("NULL");
                } else if ("9".equals(fieldNum) || "11".equals(fieldNum)) {
                    // 处理时间戳字段
                    try {
                        long timestamp = Long.parseLong(value);
                        String formattedDate = DATE_FORMAT.format(new Date(timestamp * 1000L));
                        values.add("'" + formattedDate + "'");
                    } catch (NumberFormatException e) {
                        values.add("'" + value.replace("'", "''") + "'");
                    }
                } else {
                    values.add("'" + value.replace("'", "''") + "'");
                }
            }

            if (!values.isEmpty()) {
                String insert = String.format(
                        "INSERT INTO `%s`.`%s` VALUES (%s)",
                        database, table, String.join(", ", values)
                );
                result.add(insert);
            }
        }

        return result;
    }
}

这里注意时间搓转为年月日格式。else if ("9".equals(fieldNum) || "11".equals(fieldNum))这段代码需要修改。

最后生成类似的代码:

sql 复制代码
INSERT INTO `db_iam`.`t_iam_func_auth` VALUES ('feaa322a-c7de-4c76-a07f-1d2c6d58ee37', 'FP.XZ.QUESTION.7858767', '9cd3db3c-75a0-48bf-a047-9e30deb57c33', '005f1c8a-7b9b-435d-b0cd-cc636d19f617', '9e57750d-2b2d-453b-a500-5c9e3bff2e75', '1', '0', '1a7a3bb3-eeb9-454e-b458-d2da75c9539f', '2025-05-15 10:12:31', '1a7a3bb3-eeb9-454e-b458-d2da75c9539f', '2025-05-15 10:15:34', '984ff0e4-68ad-4ca1-a1bf-d38d4f785ae5', '88c514fd-7c1f-4696-8a2c-cfa49ae1e2c2', '', '', '984ff0e4-68ad-4ca1-a1bf-d38d4f785ae5', 'XZ', '增加问卷配置人员权限', '');
INSERT INTO `db_iam`.`t_iam_func_auth` VALUES ('ff61bac9-ebb4-4fa7-bcda-016e7cb0d4bf', 'FP.XZ.QUESTION.7858656', '9ea88e7d-b92e-4c8b-a394-cb7fc6b93d9b', '39bbf469-c86b-4321-9f1c-2e7ac512bbcb', '043351b6-6ea1-4242-9085-7c4e7f9d9483', '1', '0', '605aeca6-01a8-4172-959f-34fff0cf0e67', '2025-03-26 11:32:18', '605aeca6-01a8-4172-959f-34fff0cf0e67', '2025-03-27 10:01:56', '984ff0e4-68ad-4ca1-a1bf-d38d4f785ae5', '88c514fd-7c1f-4696-8a2c-cfa49ae1e2c2', '', '', '984ff0e4-68ad-4ca1-a1bf-d38d4f785ae5', 'XZ', '系统初始化', '');

最后核对数据还原数据库数据

相关推荐
明月看潮生8 分钟前
青少年编程与数学 01-011 系统软件简介 16 Redis数据库
数据库·redis·青少年编程·编程与数学
明月看潮生10 分钟前
青少年编程与数学 01-011 系统软件简介 15 MongoDB数据库
数据库·mongodb·青少年编程·编程与数学
飞翔的佩奇24 分钟前
Java项目:基于SSM框架实现的劳务外包管理系统【ssm+B/S架构+源码+数据库+毕业论文】
java·mysql·spring·毕业设计·ssm·毕业论文·劳务外包
喵叔哟33 分钟前
第7章:Neo4j索引与约束
数据库·oracle·neo4j
Winn~1 小时前
MySQL行锁、记录锁、间隙锁、临建锁、意向锁、表锁
数据库·mysql
snowful world1 小时前
PolyU Palmprint Database掌纹识别数据集预处理(踩坑版)
数据库·人工智能·opencv
YuTaoShao1 小时前
Java八股文——MySQL「存储引擎篇」
java·开发语言·mysql
Mylvzi1 小时前
【MySQL 从 0 讲解系列】深入理解 GROUP BY 的本质与应用(含SQL示例+面试题)
数据库·sql·mysql
Forest_HAHA2 小时前
<6>-MySQL表的增删查改
数据库·mysql
blammmp2 小时前
Redis: List类型
数据库·redis·缓存