误操作后快速恢复数据 binlog 解析为反向 SQL

【binlog2sql实践】MySQL数据库binlog日志ROW格式转换标准SQL 通过binlog2sql工具,我们可以轻松地将ROW格式的binlog转化为标准SQL语句,从而方便地进行数据恢复和审计。虽然ROW格式的binlog文件较大,但它提供了更详细的数据变更信息,结合binlog2sql工具,我们可以更好地利用这些信息来维护数据库的完整性和一致性。 阅读详情

误操作后快速恢复数据 binlog 解析为反向 SQL

1.前言

本文将介绍使用 reverse_sql 工具将 GreatSQL 数据库的 binlog 解析为反向 SQL 语句。模拟误操作后,恢复数据。该工具可以帮助客户在发生事故时快速恢复数据,避免进一步的损失。使用 reverse_sql 工具非常简单,客户只需要指定肇事时间和表名即可。该工具会根据指定的时间点,在数据库中查找并还原该表在该时间点之前的数据状态。这样客户就能轻松地实现数据恢复,防止因意外操作或其他问题导致的数据丢失。

2.reverse_sql 工具简介

reverse_sql 是一个用于解析和转换二进制日志(binlog)的工具。它可以将二进制日志文件中记录的数据库更改操作(如插入、更新、删除)转换为反向的 SQL 语句,以便进行数据恢复。其运行模式需二进制日志设置为 ROW 格式。

下载地址:

https://github.com/hcymysql/reverse_sql

3.工具特点

该工具的主要功能和特点包括(针对 GreatSQL):

1、解析二进制日志:reverse_sql 能够解析 GreatSQL 的二进制日志文件,并还原出其中的 SQL 语句。

2、生成可读的 SQL:生成原始 SQL 和反向 SQL。

3、支持过滤和筛选:可以根据时间范围、表、DML操作等条件来过滤出具体的误操作 SQL 语句。

4、支持多线程并发解析 binlog 事件。

注意:reverse_sql 只是将二进制日志还原为 SQL 语句,而不会执行这些 SQL 语句来修改数据库。

4.使用前检查

4.1 GreatSQL 环境检查

首先需要确认二进制日志设置是 ROW 格式以及 row_image 是 FULL。

工具运行时,首先会进行GreatSQL的环境检测(if binlog_format != 'ROW' and binlog_row_image != 'FULL'),如果不同时满足这两个条件,程序直接退出。

greatsql> SHOW VARIABLES LIKE '%binlog%';
+------------------------------------------------+----------------------+
| Variable_name                                  | Value                |
+------------------------------------------------+----------------------+
| binlog_cache_size                              | 32768                |
| binlog_checksum                                | CRC32                |
| binlog_ddl_skip_rewrite                        | OFF                  |
| binlog_direct_non_transactional_updates        | OFF                  |
| binlog_encryption                              | OFF                  |
| binlog_error_action                            | ABORT_SERVER         |
| binlog_expire_logs_auto_purge                  | ON                   |
| binlog_expire_logs_seconds                     | 2592000              |
| binlog_format                                  | ROW                  |
| binlog_group_commit_sync_delay                 | 0                    |
| binlog_group_commit_sync_no_delay_count        | 0                    |
| binlog_gtid_simple_recovery                    | ON                   |
| binlog_max_flush_queue_time                    | 0                    |
| binlog_order_commits                           | ON                   |
| binlog_rotate_encryption_master_key_at_startup | OFF                  |
| binlog_row_event_max_size                      | 8192                 |
| binlog_row_image                               | FULL                 |
| binlog_row_metadata                            | MINIMAL              |
| binlog_row_value_options                       |                      |
| binlog_rows_query_log_events                   | OFF                  |
| binlog_skip_flush_commands                     | OFF                  |
| binlog_space_limit                             | 0                    |
| binlog_stmt_cache_size                         | 32768                |
| binlog_transaction_compression                 | OFF                  |
| binlog_transaction_compression_level_zstd      | 3                    |
| binlog_transaction_dependency_history_size     | 25000                |
| binlog_transaction_dependency_tracking         | WRITESET             |
| have_backup_safe_binlog_info                   | YES                  |
| innodb_api_enable_binlog                       | OFF                  |
| log_statements_unsafe_for_binlog               | ON                   |
| max_binlog_cache_size                          | 4294967296           |
| max_binlog_size                                | 1073741824           |
| max_binlog_stmt_cache_size                     | 18446744073709547520 |
| rpl_read_binlog_speed_limit                    | 0                    |
| sync_binlog                                    | 1                    |
+------------------------------------------------+----------------------+
35 rows in set (0.01 sec)

4.2 参数binlog_format解析

GreatSQL 支持三种二进制日志格式:

  1. STATEMENT (基于语句的复制 - SBR)

    • 记录实际执行的 SQL 语句

    • 优点:日志文件较小,记录的是语句而非数据变更

    • 缺点:某些非确定性函数(如 NOW(), UUID(), RAND())可能导致主从数据不一致

  2. ROW (基于行的复制 - RBR) GreatSQL 默认使用 ROW 作为二进制日志格式。

    • 记录每行数据的变化情况

    • 优点:最安全的复制方式,能准确复制数据变更

    • 缺点:日志文件较大,特别是批量操作时

  3. MIXED (混合模式)

    • 默认使用 STATEMENT 格式,但在某些情况下自动切换到 ROW 格式

4.3 参数binlog_row_image解析

binlog_row_image 是 GreatSQL 中控制二进制日志记录的参数,它决定了在使用基于行的复制时,二进制日志中的行镜像如何被记录。

参数选项

binlog_row_image 参数有三个可选值:

  • FULL:记录每一行的变更,包括所有列的前后镜像。–生产环境建议设置为 FULL 最佳。
  • MINIMAL:binlog日志的前镜像只记录唯一识别列(唯一索引列、主键列),后镜像只记录修改列。只记录必要的列,即在更新操作中只记录变更的列和用于识别行的最小列集。
  • NOBLOB:类似于 FULL,但不包括 BLOB 和 TEXT 类型的列,除非它们是必要的。

使用场景

  • 当设置为 FULL 时,GreatSQL 记录所有列的变更,这可以确保数据的完整性,但可能会导致二进制日志的大小增加。
  • 设置为 MINIMAL 可以减少日志的大小,因为它只记录变更的列和必要的列,这对于减少磁盘 I/O 和网络传输是有益的。
  • NOBLOB 选项适用于那些不希望记录大型 BLOB 或 TEXT 数据的场景,但仍然需要记录其他类型列的变更。

5.工具与数据库用户赋权

5.1 工具赋予执行权限

在服务器上解压后,授权:

$ ll rev*
-rwxr-xr-x 1 root root 50780824 Apr 28 14:23 reverse_sql_mysql8
$ chmod 755 reverse_sql_mysql8 

5.2 数据库用户赋权(最小化用户权限)

greatsql> CREATE USER 'test'@'%' identified BY 'test';
Query OK, 0 rows affected (0.15 sec)

greatsql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO `test`@`%`;
Query OK, 0 rows affected (0.01 sec)

greatsql> GRANT SELECT ON `test`.* TO `test`@`%`;
Query OK, 0 rows affected (0.01 sec)

greatsql> SHOW grants FOR test;
+------------------------------------------------------------------+
| Grants FOR test@%                                                |
+------------------------------------------------------------------+
| GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO `test`@`%` |
| GRANT SELECT ON `test`.* TO `test`@`%`                           |
+------------------------------------------------------------------+
2 rows in set (0.00 sec)

5.3 查看使用帮助信息

$ ./reverse_sql_mysql8 --help
usage: reverse_sql_mysql8 [-h] [-ot ONLY_TABLES [ONLY_TABLES ...]] [-op ONLY_OPERATION] -H MYSQL_HOST -P MYSQL_PORT -u MYSQL_USER -p MYSQL_PASSWD -d MYSQL_DATABASE [-c MYSQL_CHARSET] --binlog-file BINLOG_FILE
                          [--binlog-pos BINLOG_POS] --start-time ST --end-time ET [--max-workers MAX_WORKERS] [--print] [--replace] [-v]

Binlog数据恢复,生成反向SQL语句。

options:
  -h, --help            show this help message and exit
  -ot ONLY_TABLES [ONLY_TABLES ...], --only-tables ONLY_TABLES [ONLY_TABLES ...]
                        设置要恢复的表,多张表用,逗号分隔
  -op ONLY_OPERATION, --only-operation ONLY_OPERATION
                        设置误操作时的命令(insert/update/delete)
  -H MYSQL_HOST, --mysql-host MYSQL_HOST
                        MySQL主机名
  -P MYSQL_PORT, --mysql-port MYSQL_PORT
                        MySQL端口号
  -u MYSQL_USER, --mysql-user MYSQL_USER
                        MySQL用户名
  -p MYSQL_PASSWD, --mysql-passwd MYSQL_PASSWD
                        MySQL密码
  -d MYSQL_DATABASE, --mysql-database MYSQL_DATABASE
                        MySQL数据库名
  -c MYSQL_CHARSET, --mysql-charset MYSQL_CHARSET
                        MySQL字符集,默认utf8
  --binlog-file BINLOG_FILE
                        Binlog文件
  --binlog-pos BINLOG_POS
                        Binlog位置,默认4
  --start-time ST       起始时间
  --end-time ET         结束时间
  --max-workers MAX_WORKERS
                        线程数,默认4(并发越高,锁的开销就越大,适当调整并发数)
  --print               将解析后的SQL输出到终端
  --replace             将update转换为replace操作
  -v, --version         show program's version number and exit

Example usage:
    shell> ./reverse_sql -ot table1 -op delete -H 192.168.198.239 -P 3336 -u admin -p hechunyang -d hcy \
            --binlog-file mysql-bin.000124 --start-time "2023-07-06 10:00:00" --end-time "2023-07-06 22:00:00" 

6.案例演示

6.1 创建测试数据,模拟误更新

greatsql> CREATE TABLE t1 (  
         id INT AUTO_INCREMENT PRIMARY KEY,  
         name VARCHAR(50),  
         age INT,  
         email VARCHAR(100),  
         gender ENUM('Male', 'Female', 'Other'),  
         salary DECIMAL(10,2),  
         join_date DATE,  
         is_active BOOLEAN  
     );
Query OK, 0 rows affected (0.04 sec)

greatsql> INSERT INTO t1 (name, age, email, gender, salary, join_date, is_active) VALUES  
     ('张三', 28, 'zhangsan@example.com', 'Male', 8500.00, '2020-05-15', TRUE),  
     ('李四', 32, 'lisi@example.com', 'Male', 9200.50, '2019-08-22', TRUE),  
     ('王五', 25, 'wangwu@example.com', 'Male', 7800.00, '2021-03-10', TRUE),  
     ('赵六', 29, 'zhaoliu@example.com', 'Female', 8800.75, '2020-11-05', TRUE),  
     ('肖七', 35, 'xiaoqi@example.com', 'Female', 10500.00, '2018-06-18', FALSE),  
     ('孙八', 27, 'sunba@example.com', 'Male', 8100.00, '2021-01-30', TRUE),  
     ('周九', 31, 'zhoujiu@example.com', 'Other', 9500.25, '2019-09-12', TRUE),  
     ('吴十', 24, 'wushi@example.com', 'Female', 7600.50, '2022-02-14', TRUE),  
     ('郑十一', 30, 'zhengshiyi@example.com', 'Male', 8900.00, '2020-07-25', FALSE),  
     ('王十二', 33, 'wangshier@example.com', 'Female', 10000.00, '2019-04-08', TRUE);
Query OK, 10 rows affected (0.01 sec)
Records: 10  Duplicates: 0  Warnings: 0

greatsql> SELECT * FROM t1;
+----+-----------+------+------------------------+--------+----------+------------+-----------+
| id | name      | age  | email                  | gender | salary   | join_date  | is_active |
+----+-----------+------+------------------------+--------+----------+------------+-----------+
|  1 | 张三      |   28 | zhangsan@example.com   | Male   |  8500.00 | 2020-05-15 |         1 |
|  2 | 李四      |   32 | lisi@example.com       | Male   |  9200.50 | 2019-08-22 |         1 |
|  3 | 王五      |   25 | wangwu@example.com     | Male   |  7800.00 | 2021-03-10 |         1 |
|  4 | 赵六      |   29 | zhaoliu@example.com    | Female |  8800.75 | 2020-11-05 |         1 |
|  5 | 肖七      |   35 | xiaoqi@example.com     | Female | 10500.00 | 2018-06-18 |         0 |
|  6 | 孙八      |   27 | sunba@example.com      | Male   |  8100.00 | 2021-01-30 |         1 |
|  7 | 周九      |   31 | zhoujiu@example.com    | Other  |  9500.25 | 2019-09-12 |         1 |
|  8 | 吴十      |   24 | wushi@example.com      | Female |  7600.50 | 2022-02-14 |         1 |
|  9 | 郑十一    |   30 | zhengshiyi@example.com | Male   |  8900.00 | 2020-07-25 |         0 |
| 10 | 王十二    |   33 | wangshier@example.com  | Female | 10000.00 | 2019-04-08 |         1 |
+----+-----------+------+------------------------+--------+----------+------------+-----------+
10 rows in set (0.00 sec)

greatsql> UPDATE t1   
     SET salary = 9800.00, is_active = TRUE   
     WHERE id = 5;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

greatsql> SELECT * FROM t1;
+----+-----------+------+------------------------+--------+----------+------------+-----------+
| id | name      | age  | email                  | gender | salary   | join_date  | is_active |
+----+-----------+------+------------------------+--------+----------+------------+-----------+
|  1 | 张三      |   28 | zhangsan@example.com   | Male   |  8500.00 | 2020-05-15 |         1 |
|  2 | 李四      |   32 | lisi@example.com       | Male   |  9200.50 | 2019-08-22 |         1 |
|  3 | 王五      |   25 | wangwu@example.com     | Male   |  7800.00 | 2021-03-10 |         1 |
|  4 | 赵六      |   29 | zhaoliu@example.com    | Female |  8800.75 | 2020-11-05 |         1 |
|  5 | 肖七      |   35 | xiaoqi@example.com     | Female |  9800.00 | 2018-06-18 |         1 |
|  6 | 孙八      |   27 | sunba@example.com      | Male   |  8100.00 | 2021-01-30 |         1 |
|  7 | 周九      |   31 | zhoujiu@example.com    | Other  |  9500.25 | 2019-09-12 |         1 |
|  8 | 吴十      |   24 | wushi@example.com      | Female |  7600.50 | 2022-02-14 |         1 |
|  9 | 郑十一    |   30 | zhengshiyi@example.com | Male   |  8900.00 | 2020-07-25 |         0 |
| 10 | 王十二    |   33 | wangshier@example.com  | Female | 10000.00 | 2019-04-08 |         1 |
+----+-----------+------+------------------------+--------+----------+------------+-----------+
10 rows in set (0.00 sec)

6.2 解析binlog

查看 binlog 当前信息

greatsql> SHOW MASTER STATUS \G
*************************** 1. row ***************************
             File: binlog.000002
         Position: 2918
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 2a3248f7-e762-11ef-ae09-00163e11ac96:1,
3837053e-e762-11ef-ade8-00163e2cc6be:1-4008,
615fadb3-234d-11f0-ab29-00163e2cc6be:1-5,
aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa1:1-1067166
1 row in set (0.00 sec)

执行解析命令

 ./reverse_sql_mysql8 -u 'test' -p 'test' -H 172.17.136.70 -P 3301 -d test_111 -ot t1 --binlog-file /greatsql/dbdata/3301/log/binlog.000009 --start-time "2025-05-22 16:30:00" --end-time "2025-05-22 16:40:00"
 Processing binlogevents: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 50.32event/s]
Processing binlogevents: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 2/2 [00:00<00:00, 111.72event/s]
Processing binlogevents: 0event [00:00, ?event/s]
Processing binlogevents: 0event [00:00, ?event/s]

当出现误操作时,只需指定误操作的时间段,其对应的 binlog 文件(通常可以通过 show master status 得到当前的 binlog 文件名)以及刚才误操作的表,和具体的 DML 命令,比如 update 或者 delete。【不支持一次解析多个 binlog】

6.3 查看解析文件

$ ll test*
-rw-r--r-- 1 root root 5892 Apr 28 15:47 test_111_t1_recover_2025-04-28_15:47:17.sql
$ 
$ cat test_111_t1_recover_2025-04-28_15:47:17.sql 
-- SQL执行时间:2025-04-28 15:41:32
-- 原生sql:
         -- INSERT INTO `test_111`.`t1`(`id`,`name`,`age`,`email`,`gender`,`salary`,`join_date`,`is_active`) VALUES (1,'张三',28,'zhangsan@example.com','Male',8500.00,'2020-05-15',1);
-- 回滚sql:
         DELETE FROM `test_111`.`t1` WHERE `id`=1 AND `name`='张三' AND `age`=28 AND `email`='zhangsan@example.com' AND `gender`='Male' AND `salary`=8500.00 AND `join_date`='2020-05-15' AND `is_active`=1;
-- ----------------------------------------------------------
-- SQL执行时间:2025-04-28 15:41:32
-- 原生sql:
         -- INSERT INTO `test_111`.`t1`(`id`,`name`,`age`,`email`,`gender`,`salary`,`join_date`,`is_active`) VALUES (2,'李四',32,'lisi@example.com','Male',9200.50,'2019-08-22',1);
-- 回滚sql:
         DELETE FROM `test_111`.`t1` WHERE `id`=2 AND `name`='李四' AND `age`=32 AND `email`='lisi@example.com' AND `gender`='Male' AND `salary`=9200.50 AND `join_date`='2019-08-22' AND `is_active`=1;
-- ----------------------------------------------------------
-- SQL执行时间:2025-04-28 15:41:32
-- 原生sql:
         -- INSERT INTO `test_111`.`t1`(`id`,`name`,`age`,`email`,`gender`,`salary`,`join_date`,`is_active`) VALUES (3,'王五',25,'wangwu@example.com','Male',7800.00,'2021-03-10',1);
-- 回滚sql:
         DELETE FROM `test_111`.`t1` WHERE `id`=3 AND `name`='王五' AND `age`=25 AND `email`='wangwu@example.com' AND `gender`='Male' AND `salary`=7800.00 AND `join_date`='2021-03-10' AND `is_active`=1;
-- ----------------------------------------------------------
-- SQL执行时间:2025-04-28 15:41:32
-- 原生sql:
         -- INSERT INTO `test_111`.`t1`(`id`,`name`,`age`,`email`,`gender`,`salary`,`join_date`,`is_active`) VALUES (4,'赵六',29,'zhaoliu@example.com','Female',8800.75,'2020-11-05',1);
-- 回滚sql:
         DELETE FROM `test_111`.`t1` WHERE `id`=4 AND `name`='赵六' AND `age`=29 AND `email`='zhaoliu@example.com' AND `gender`='Female' AND `salary`=8800.75 AND `join_date`='2020-11-05' AND `is_active`=1;
-- ----------------------------------------------------------
-- SQL执行时间:2025-04-28 15:41:32
-- 原生sql:
         -- INSERT INTO `test_111`.`t1`(`id`,`name`,`age`,`email`,`gender`,`salary`,`join_date`,`is_active`) VALUES (5,'肖七',35,'xiaoqi@example.com','Female',10500.00,'2018-06-18',0);
-- 回滚sql:
         DELETE FROM `test_111`.`t1` WHERE `id`=5 AND `name`='肖七' AND `age`=35 AND `email`='xiaoqi@example.com' AND `gender`='Female' AND `salary`=10500.00 AND `join_date`='2018-06-18' AND `is_active`=0;
-- ----------------------------------------------------------
-- SQL执行时间:2025-04-28 15:41:32
-- 原生sql:
         -- INSERT INTO `test_111`.`t1`(`id`,`name`,`age`,`email`,`gender`,`salary`,`join_date`,`is_active`) VALUES (6,'孙八',27,'sunba@example.com','Male',8100.00,'2021-01-30',1);
-- 回滚sql:
         DELETE FROM `test_111`.`t1` WHERE `id`=6 AND `name`='孙八' AND `age`=27 AND `email`='sunba@example.com' AND `gender`='Male' AND `salary`=8100.00 AND `join_date`='2021-01-30' AND `is_active`=1;
-- ----------------------------------------------------------
-- SQL执行时间:2025-04-28 15:41:32
-- 原生sql:
         -- INSERT INTO `test_111`.`t1`(`id`,`name`,`age`,`email`,`gender`,`salary`,`join_date`,`is_active`) VALUES (7,'周九',31,'zhoujiu@example.com','Other',9500.25,'2019-09-12',1);
-- 回滚sql:
         DELETE FROM `test_111`.`t1` WHERE `id`=7 AND `name`='周九' AND `age`=31 AND `email`='zhoujiu@example.com' AND `gender`='Other' AND `salary`=9500.25 AND `join_date`='2019-09-12' AND `is_active`=1;
-- ----------------------------------------------------------
-- SQL执行时间:2025-04-28 15:41:32
-- 原生sql:
         -- INSERT INTO `test_111`.`t1`(`id`,`name`,`age`,`email`,`gender`,`salary`,`join_date`,`is_active`) VALUES (8,'吴十',24,'wushi@example.com','Female',7600.50,'2022-02-14',1);
-- 回滚sql:
         DELETE FROM `test_111`.`t1` WHERE `id`=8 AND `name`='吴十' AND `age`=24 AND `email`='wushi@example.com' AND `gender`='Female' AND `salary`=7600.50 AND `join_date`='2022-02-14' AND `is_active`=1;
-- ----------------------------------------------------------
-- SQL执行时间:2025-04-28 15:41:32
-- 原生sql:
         -- INSERT INTO `test_111`.`t1`(`id`,`name`,`age`,`email`,`gender`,`salary`,`join_date`,`is_active`) VALUES (9,'郑十一',30,'zhengshiyi@example.com','Male',8900.00,'2020-07-25',0);
-- 回滚sql:
         DELETE FROM `test_111`.`t1` WHERE `id`=9 AND `name`='郑十一' AND `age`=30 AND `email`='zhengshiyi@example.com' AND `gender`='Male' AND `salary`=8900.00 AND `join_date`='2020-07-25' AND `is_active`=0;
-- ----------------------------------------------------------
-- SQL执行时间:2025-04-28 15:41:32
-- 原生sql:
         -- INSERT INTO `test_111`.`t1`(`id`,`name`,`age`,`email`,`gender`,`salary`,`join_date`,`is_active`) VALUES (10,'王十二',33,'wangshier@example.com','Female',10000.00,'2019-04-08',1);
-- 回滚sql:
         DELETE FROM `test_111`.`t1` WHERE `id`=10 AND `name`='王十二' AND `age`=33 AND `email`='wangshier@example.com' AND `gender`='Female' AND `salary`=10000.00 AND `join_date`='2019-04-08' AND `is_active`=1;
-- ----------------------------------------------------------
-- SQL执行时间:2025-04-28 15:41:57
-- 原生sql:
         -- UPDATE `test_111`.`t1` SET `id`=5,`name`='肖七',`age`=35,`email`='xiaoqi@example.com',`gender`='Female',`salary`=9800.00,`join_date`='2018-06-18',`is_active`=1 WHERE `id`=5 AND `name`='肖七' AND `age`=35 AND `email`='xiaoqi@example.com' AND `gender`='Female' AND `salary`=10500.00 AND `join_date`='2018-06-18' AND `is_active`=0;
-- 回滚sql:
         UPDATE `test_111`.`t1` SET `id`=5,`name`='肖七',`age`=35,`email`='xiaoqi@example.com',`gender`='Female',`salary`=10500.00,`join_date`='2018-06-18',`is_active`=0 WHERE `id`=5 AND `name`='肖七' AND `age`=35 AND `email`='xiaoqi@example.com' AND `gender`='Female' AND `salary`=9800.00 AND `join_date`='2018-06-18' AND `is_active`=1;
-- ----------------------------------------------------------
$ 

工具运行后,会在当前目录下生成一个 {db}_{table}_recover.sql 文件,保存着原生 SQL(原生 SQL 会加注释) 和反向 SQL,如果想将结果输出到前台终端,可以指定 --print 选项。

$ ./reverse_sql_mysql8 -u 'test' -p 'test' -H 172.17.136.70 -P 3301 -d test_111 -ot t1 --binlog-file /greatsql/dbdata/3301/log/binlog.000008 --start-time "2025-05-21 11:10:00" --end-time "2025-05-21 11:18:00" --print
Processing binlogevents: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 4/4 [00:00<00:00, 258.00event/s]
Processing binlogevents: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 4/4 [00:00<00:00, 292.57event/s]
Processing binlogevents: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 277.56event/s]
Processing binlogevents: 0event [00:00, ?event/s]
-- SQL执行时间:2025-05-21 11:14:01 
-- 原生sql:
         -- INSERT INTO `test_111`.`t1`(`id`,`name`,`age`,`email`,`gender`,`salary`,`join_date`,`is_active`) VALUES (1,'张三',28,'zhangsan@example.com','Male',8500.00,'2020-05-15',1); 
-- 回滚sql:
         DELETE FROM `test_111`.`t1` WHERE `id`=1 AND `name`='张三' AND `age`=28 AND `email`='zhangsan@example.com' AND `gender`='Male' AND `salary`=8500.00 AND `join_date`='2020-05-15' AND `is_active`=1;
-- ----------------------------------------------------------

-- SQL执行时间:2025-05-21 11:14:01 
-- 原生sql:
         -- INSERT INTO `test_111`.`t1`(`id`,`name`,`age`,`email`,`gender`,`salary`,`join_date`,`is_active`) VALUES (2,'李四',32,'lisi@example.com','Male',9200.50,'2019-08-22',1); 
-- 回滚sql:
         DELETE FROM `test_111`.`t1` WHERE `id`=2 AND `name`='李四' AND `age`=32 AND `email`='lisi@example.com' AND `gender`='Male' AND `salary`=9200.50 AND `join_date`='2019-08-22' AND `is_active`=1;
-- ----------------------------------------------------------

如果你想把 update 操作转换为 replace,指定 --replace 选项即可,同时会在当前目录下生成一个{db}_{table}_recover_replace.sql 文件。

$ ./reverse_sql_mysql8 -u 'test' -p 'test' -H 172.17.136.70 -P 3301 -d test_111 -ot t1 --binlog-file /greatsql/dbdata/3301/log/binlog.000008 --start-time "2025-05-21 11:10:00" --end-time "2025-05-21 11:18:00" --replace
Processing binlogevents: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 4/4 [00:00<00:00, 83.25event/s]
Processing binlogevents: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 4/4 [00:00<00:00, 112.54event/s]
Processing binlogevents: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 172.61event/s]
Processing binlogevents: 0event [00:00, ?event/s]
$ ll
-rwxr-xr-x 1 root    root    50780824 May 21 10:28 reverse_sql_mysql8
-rw-r--r-- 1 root    root         646 May 21 11:19 test_111_t1_recover_2025-05-21_11:19:28_replace.sql
-rw-r--r-- 1 root    root        5892 May 21 11:19 test_111_t1_recover_2025-05-21_11:19:28.sql
$ cat test_111_t1_recover_2025-05-21_11:19:28_replace.sql 
-- SQL执行时间:2025-05-21 11:14:36
-- 原生sql:
         -- UPDATE `test_111`.`t1` SET `id`=5,`name`='钱七',`age`=35,`email`='xiaoqi@example.com',`gender`='Female',`salary`=9800.00,`join_date`='2018-06-18',`is_active`=1 WHERE `id`=5 AND `name`='钱七' AND `age`=35 AND `email`='xiaoqi@example.com' AND `gender`='Female' AND `salary`=10500.00 AND `join_date`='2018-06-18' AND `is_active`=0;
-- 回滚sql:
         REPLACE INTO `test_111`.`t1` (`id`,`name`,`age`,`email`,`gender`,`salary`,`join_date`,`is_active`) VALUES (5,'钱七',35,'xiaoqi@example.com','Female',10500.00,'2018-06-18',0);
-- ----------------------------------------------------------

但注意,如果字段值中包含换行符,则原生 SQL 后几行不会被注释,需要手动处理。

6.4 拿到反向SQL恢复数据

在{db}_{table}_recover.sql 文件中找到刚才误操作的 DML 语句,然后在 GreatSQL 数据库中执行逆向工程后的 SQL 以恢复数据。

-- SQL执行时间:2025-04-28 15:41:57
-- 原生sql:
         -- UPDATE `test_111`.`t1` SET `id`=5,`name`='肖七',`age`=35,`email`='xiaoqi@example.com',`gender`='Female',`salary`=9800.00,`join_date`='2018-06-18',`is_active`=1 WHERE `id`=5 AND `name`='肖七' AND `age`=35 AND `email`='xiaoqi@example.com' AND `gender`='Female' AND `salary`=10500.00 AND `join_date`='2018-06-18' AND `is_active`=0;
-- 回滚sql:
         UPDATE `test_111`.`t1` SET `id`=5,`name`='肖七',`age`=35,`email`='xiaoqi@example.com',`gender`='Female',`salary`=10500.00,`join_date`='2018-06-18',`is_active`=0 WHERE `id`=5 AND `name`='肖七' AND `age`=35 AND `email`='xiaoqi@example.com' AND `gender`='Female' AND `salary`=9800.00 AND `join_date`='2018-06-18' AND `is_active`=1;
greatsql> UPDATE `test_111`.`t1` SET `id`=5,`name`='肖七',`age`=35,`email`='xiaoqi@example.com',`gender`='Female',`salary`=10500.00,`join_date`='2018-06-18',`is_active`=0 WHERE `id`=5 AND `name`='肖七' AND `age`=35 AND `email`='xiaoqi@example.com' AND `gender`='Female' AND `salary`=9800.00 AND `join_date`='2018-06-18' AND `is_active`=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

greatsql> SELECT * FROM t1;
+----+-----------+------+------------------------+--------+----------+------------+-----------+
| id | name      | age  | email                  | gender | salary   | join_date  | is_active |
+----+-----------+------+------------------------+--------+----------+------------+-----------+
|  1 | 张三      |   28 | zhangsan@example.com   | Male   |  8500.00 | 2020-05-15 |         1 |
|  2 | 李四      |   32 | lisi@example.com       | Male   |  9200.50 | 2019-08-22 |         1 |
|  3 | 王五      |   25 | wangwu@example.com     | Male   |  7800.00 | 2021-03-10 |         1 |
|  4 | 赵六      |   29 | zhaoliu@example.com    | Female |  8800.75 | 2020-11-05 |         1 |
|  5 | 肖七      |   35 | xiaoqi@example.com     | Female | 10500.00 | 2018-06-18 |         0 |
|  6 | 孙八      |   27 | sunba@example.com      | Male   |  8100.00 | 2021-01-30 |         1 |
|  7 | 周九      |   31 | zhoujiu@example.com    | Other  |  9500.25 | 2019-09-12 |         1 |
|  8 | 吴十      |   24 | wushi@example.com      | Female |  7600.50 | 2022-02-14 |         1 |
|  9 | 郑十一    |   30 | zhengshiyi@example.com | Male   |  8900.00 | 2020-07-25 |         0 |
| 10 | 王十二    |   33 | wangshier@example.com  | Female | 10000.00 | 2019-04-08 |         1 |
+----+-----------+------+------------------------+--------+----------+------------+-----------+
10 rows in set (0.00 sec)

可以看到这条误更新的数据已经恢复到最初状态。

如果 {db}_{table}_recover.sql 文件的内容过多,也可以通过 awk 命令进行分割,以便更容易进行排查。

$ awk '/^-- SQL执行时间/{filename = "output" ++count ".sql"; print > filename; next} {print > filename}' test_111_t1_recover_2025-04-28_15:47:17.sql
$ ll output*
-rw-r--r-- 1 root root 524 Apr 28 16:22 output10.sql
-rw-r--r-- 1 root root 802 Apr 28 16:22 output11.sql
-rw-r--r-- 1 root root 508 Apr 28 16:22 output1.sql
-rw-r--r-- 1 root root 500 Apr 28 16:22 output2.sql
-rw-r--r-- 1 root root 504 Apr 28 16:22 output3.sql
-rw-r--r-- 1 root root 510 Apr 28 16:22 output4.sql
-rw-r--r-- 1 root root 510 Apr 28 16:22 output5.sql
-rw-r--r-- 1 root root 502 Apr 28 16:22 output6.sql
-rw-r--r-- 1 root root 508 Apr 28 16:22 output7.sql
-rw-r--r-- 1 root root 506 Apr 28 16:22 output8.sql
-rw-r--r-- 1 root root 518 Apr 28 16:22 output9.sql
$ cat output1.sql
-- SQL执行时间:2025-04-28 15:41:32
-- 原生sql:
         -- INSERT INTO `test_111`.`t1`(`id`,`name`,`age`,`email`,`gender`,`salary`,`join_date`,`is_active`) VALUES (1,'张三',28,'zhangsan@example.com','Male',8500.00,'2020-05-15',1);
-- 回滚sql:
         DELETE FROM `test_111`.`t1` WHERE `id`=1 AND `name`='张三' AND `age`=28 AND `email`='zhangsan@example.com' AND `gender`='Male' AND `salary`=8500.00 AND `join_date`='2020-05-15' AND `is_active`=1;
-- ----------------------------------------------------------
$ 

不支持 drop 和 truncate 操作,因为这两个操作属于物理性删除,需要通过历史备份进行恢复。

可能存在的问题:

  • 数据库密码含特殊字符:需要加单引号圈起来;
  • 数据库字段中如有换行符或者其他特殊字符,则原生sql显示的时候后面可能不会注释,导致回滚 sql 错乱。因此需要我们将原生 SQL 用正则替换,即“-- 原生sql:”和“-- 回滚sql:”之间的部分(-- 原生sql:.*?-- 回滚sql:)

7.reverse_sql与binlog2sql主要区别

7.1 reverse_sql工具解析

./reverse_sql_mysql8 --help
usage: reverse_sql_mysql8 [-h] [-ot ONLY_TABLES [ONLY_TABLES ...]] [-op ONLY_OPERATION] -H MYSQL_HOST -P MYSQL_PORT -u MYSQL_USER -p MYSQL_PASSWD -d MYSQL_DATABASE [-c MYSQL_CHARSET] --binlog-file BINLOG_FILE
                          [--binlog-pos BINLOG_POS] --start-time ST --end-time ET [--max-workers MAX_WORKERS] [--print] [--replace] [-v]

Binlog数据恢复,生成反向SQL语句。

options:
  -h, --help            show this help message and exit
  -ot ONLY_TABLES [ONLY_TABLES ...], --only-tables ONLY_TABLES [ONLY_TABLES ...]
                        设置要恢复的表,多张表用,逗号分隔
  -op ONLY_OPERATION, --only-operation ONLY_OPERATION
                        设置误操作时的命令(insert/update/delete)
  -H MYSQL_HOST, --mysql-host MYSQL_HOST
                        MySQL主机名
  -P MYSQL_PORT, --mysql-port MYSQL_PORT
                        MySQL端口号
  -u MYSQL_USER, --mysql-user MYSQL_USER
                        MySQL用户名
  -p MYSQL_PASSWD, --mysql-passwd MYSQL_PASSWD
                        MySQL密码
  -d MYSQL_DATABASE, --mysql-database MYSQL_DATABASE
                        MySQL数据库名
  -c MYSQL_CHARSET, --mysql-charset MYSQL_CHARSET
                        MySQL字符集,默认utf8
  --binlog-file BINLOG_FILE
                        Binlog文件
  --binlog-pos BINLOG_POS
                        Binlog位置,默认4
  --start-time ST       起始时间
  --end-time ET         结束时间
  --max-workers MAX_WORKERS
                        线程数,默认4(并发越高,锁的开销就越大,适当调整并发数)
  --print               将解析后的SQL输出到终端
  --replace             将update转换为replace操作
  -v, --version         show program's version number and exit

Example usage:
    shell> ./reverse_sql -ot table1 -op delete -H 192.168.198.239 -P 3336 -u admin -p hechunyang -d hcy \
            --binlog-file mysql-bin.000124 --start-time "2023-07-06 10:00:00" --end-time "2023-07-06 22:00:00" 

7.2 binlog2sql 工具解析

python binlog2sql.py --help
解析模式: 
--stop-never 持续解析binlog。可选。默认False,同步至执行命令时最新的binlog位置。 
-K, --no-primary-key 对INSERT语句去除主键。可选。默认False 
-B, --flashback 生成回滚SQL,可解析大文件,不受内存限制。可选。默认False。与stop-never或no-primary-key不能同时添加。 
--back-interval -B模式下,每打印一千行回滚SQL,加一句SLEEP多少秒,如不想加SLEEP,请设为0。可选。默认1.0。
解析范围控制: 
--start-file 起始解析文件,只需文件名,无需全路径 。必须。 
--start-position/--start-pos 起始解析位置。可选。默认为start-file的起始位置。 
--stop-file/--end-file 终止解析文件。可选。默认为start-file同一个文件。若解析模式为stop-never,此选项失效。 
--stop-position/--end-pos 终止解析位置。可选。默认为stop-file的最末位置;若解析模式为stop-never,此选项失效。 
--start-datetime 起始解析时间,格式'%Y-%m-%d %H:%M:%S'。可选。默认不过滤。 
--stop-datetime 终止解析时间,格式'%Y-%m-%d %H:%M:%S'。可选。默认不过滤。
对象过滤: 
-d, --databases 只解析目标db的sql,多个库用空格隔开,如-d db1 db2。可选。默认为空。 
-t, --tables 只解析目标table的sql,多张表用空格隔开,如-t tbl1 tbl2。可选。默认为空。 
--only-dml 只解析dml,忽略ddl。可选。默认False。 
--sql-type 只解析指定类型,支持INSERT, UPDATE, DELETE。多个类型用空格隔开,如--sql-type INSERT DELETE。可选。默认为增删改都解析。用了此参数但没填任何类型,则三者都不解析。

7.3 两个工具的区别

核心功能对比

特性reverse_sqlbinlog2sql
生成方向专注反向SQL (UNDO)默认正向SQL,需加 -B 参数生成反向SQL
输出格式直接生成可执行的回滚SQL可选原始SQL/回滚SQL/带注释的SQL
过滤条件基础过滤(时间/表名)更灵活(GTID/position/库名等)
大文件处理未明确说明明确支持大文件(-B 模式不受内存限制)
时间范围必须指定 --start-time 和 --end-time可选(支持按时间或位置过滤)
并发控制支持线程数调节(–max-workers)无并发控制选项
断点续传依赖binlog位置(–binlog-pos)支持更灵活的起止位置(–start-pos/–end-pos)
表级过滤支持(-ot 多表逗号分隔)支持(-t 多表空格分隔)
操作类型过滤必须指定(-op 仅限一种操作)灵活过滤(–sql-type 可多选或留空)
DDL忽略不支持支持(–only-dml 忽略DDL)
输出控制终端打印(–print)或直接执行默认打印,支持回滚SLEEP间隔(–back-interval)
主键处理无相关选项支持去除主键(-K 模式)
UPDATE转换支持转REPLACE(–replace)无此功能
  1. 数据恢复方向
    1. reverse_sql:专门用于生成反向 SQL(UNDO SQL),主要用于数据回滚/修复场景
    2. binlog2sql:默认生成正向 SQL,也可通过参数生成反向 SQL
  2. 实现方式
    1. reverse_sql 基于 Python 实现
    2. binlog2sql 也是 Python 实现但更早出现
  3. 使用场景
    1. 选 reverse_sql :
      ✅ 需要快速生成精准回滚 SQL(需明确操作类型和时间范围)
      ✅ 处理大型事务(自动分组优化)
    2. 选 binlog2sql :
      ✅ 需要分析 binlog 详细内容(支持实时解析)
      ✅持续监控或复杂过滤条件(多操作类型组合过滤,如 GTID / 多库多表)
      ✅ 大 binlog 文件处理,优先 binlog2sql -B(内存优化更可靠)

8.总结

reverse_sql 在生成回滚 SQL 时更加灵活和高效。reverse_sql 数据闪回工具为数据库管理和维护提供了极大的便利,特别是在数据恢复方面。它允许用户在发生错误时能够迅速采取行动,减少数据丢失带来的损失。然而,为了有效使用此工具,必须注意其实施条件,如确保日志记录功能正常运行,以及维护良好的备份习惯。此外,了解工具的具体操作方法及其限制也非常重要,这有助于更安全、高效地管理数据库资源。

binlog解析工具——binlog2sql binlog2sql是一款开源的 Python 工具,用于解析 MySQL 的 binlog 文件,生成标准 SQL 或回滚 SQL,实现数据恢复和衍生功能。数据快速回滚(闪回):通过解析 binlog 生成反向 SQL,恢复误删除或误修改的数据。主从切换修复:当主从切换后新主库数据丢失时,通过 binlog 恢复数据一致性。生成标准 SQL:用于审计、数据迁移或分析数据库操作历史。 阅读详情

相关推荐

binlog 解析工具——my2sql

my2sql是一款基于 Go 语言开发的 MySQL binlog 解析工具,支持从二进制日志(binlog)中生成原始 SQL、回滚 SQL(闪回 SQL)、去除主键的 INSERT SQL 等,还能生成 DML 操作统计信息。数据快速回滚(闪回):通过逆向解析 binlog 生成反向 SQL,恢复误删除或误修改的数据。主从数据一致性修复:主从切换后新主库数据丢失时,通过 binlog 恢复数据。生成标准 SQL 与统计信息:用于审计、数据迁移,或分析高频更新表、大事务及主从延迟问题。

翔云 1568

mysql bin日志转sql文件方法

用mysqlbinlog命令去执行。

zpf_07的博客 5214

数据误删急救指南:3步用binlog日志恢复truncate/drop操作,你的数据还能救回来吗?

摘要: MySQL的binlog日志是应对误删操作(如TRUNCATE/DROP)的核心工具,通过记录所有写操作实现秒级数据恢复。本文详解3步恢复流程:1)确认binlog配置;2)解析日志定位误删事件;3)构建反向SQL回滚。关键技巧包括GTID加速定位、正则过滤高危操作,并对比传统备份(小时级)与binlog恢复(分钟级)的优劣。针对binlog过期、主从同步异常等隐患,提出自动化脚本与云服务解决方案,强调ROW格式日志对100%数据恢复的必要性。适用于高频写入场景的紧急救援,需配合定期归档与测试验证确

java专栏 896

MYSQL中sql_log_bin变量在复制中的特殊用途

SQL_LOG_BIN = {ON | OFF} 如果在一连接线种中将该值设置为OFF,则该连接上客户端的所有更新操作在MYSQL二进制日志中不会记录日志。 在双MASTER的复制结构中,原生的MYSQL复制中是不会出现循环复制的,因为可以判断server-id来决定 但是如用一种第三方的工具,模拟SLAVE连接MASTER获取binlog,然后这个工具再连接真正的SLAVE,将

很多时候,你缺少的不是知识而是热情 2942

Mysql,log_bin 与 sql_log_bin的区别

log_bin:二进制日志。 说白了,就是把把在mysql里面执行的语句,记录在二进制日志里面而已。 那么这些二进制日志有什么作用,你知道吗? 1:数据恢复  如果你的数据库出问题了,而你之前有过备份,那么可以看日志文件,找出是哪个命令导致你的数据库出问题了,想办法挽回损失。 而且,你也可以利用二进制日志来还原你误操作的数据库。不过具体怎么操作还需要学的哟! 2:主从服务器之间同步数

Top5软件工程硕士,先后在京东、字节从事多年Java后端开发、实时和离线大数据开发 1万+

中国区ASP服务性规范考试

10、每次现场维护服务,工程师需按照400要求达到现场的时间与客户联系,在抵达现场、故障恢复后两个时间点分别向400报CALL ,如与客户联系变更到现场时间点,也需向400电话备案(400-822-9999)……20、工程师小B 在接到客户故障申报后赶到客户现场,发现问题无法解决,于是及时将情况反馈至技术支持响应工程师小C ,小B 就和小C 协商由小C 远程解决此问题,后小B 离开客户现场。18、小L 到客户现场交付安装服务。6、EPMS 中上载初验证书的命名规则为:合同号+初验的客户签署日期……

2301_76197693的博客 1909

mysql bin 日志转成sql

首先确定mysql binlog 服务开启。本地找到mysql安装位置的bin目录。在窗口路径处直接输入cmd。找到binlog日志。

qq_32037561的博客 2941

深入解析达梦数据库核心技术:检查点、redo、undo、MVCC与内存缓存刷盘

MVCC 依赖 undo 日志:通过 undo 日志构建版本链,实现 “读不加锁”;刷盘依赖检查点:检查点批量清理脏页,redo 日志通过检查点释放空间;日志保障刷盘安全:redo 日志先行写入,确保未刷盘脏页可恢复;刷盘优化 MVCC 性能:优先刷冷区脏页,减少对高频访问数据的影响。例如,一个完整的 “查询 - 修改 - 提交 - 恢复” 流程中:查询时,MVCC 通过 undo 日志获取可见版本,无需等待锁;修改时,redo/undo 日志先记录,缓冲池生成脏页;

tangyuan12345678的博客 1415

MySQL利用binlog恢复误操作数据(python脚本)

在人工手动进行一些数据库写操作的时候(比方说数据订正),尤其是一些不可控的批量更新或删除,通常都建议备份后操作。不过不怕万一,就怕一万,有备无患总是好的。在线上或者测试环境误操作导致数据被删除或者更新后,想要恢复,一般有两种方法。 方法一、利用最近的全量备份+增量binlog备份,恢复到误操作之前的状态,但是随着数据量的增大,binlog的增多,恢复起来很费时。方法二、如果binlo...

weixin_30518397的博客 348

【遥感数字图像处理(朱文泉)】第四章 变换域处理方法

变换域的处理方法

甜子yu的博客 4311

ZYNQ实战:手把手教你用AXI4-Full IP核打通PL与PS的DDR数据通道

本文提供了一份详细的ZYNQ实战指南,手把手教你创建并使用具备AXI4-Full Master接口的自定义IP核,实现PL(可编程逻辑)通过AXI HP接口直接读写PS(处理系统)的DDR内存。文章涵盖了从Vivado硬件设计、IP核配置、地址映射到Vitis软件验证的完整流程,并深入解析了数据一致性(禁用Cache)等关键要点,旨在帮助开发者掌握ZYNQ异构计算中高效数据搬运的核心技术。

weixin_29193359的博客 284

MySQL数据误删恢复终极指南:drop表与delete操作完美救赎

MySQL 数据误删恢复的核心是「备份 + 日志」:drop 表依赖全备 + Binlog 组合,delete 可通过 my2sql 快速回滚。但最有效的方案永远是「预防为主,应急为辅」—— 日常做好备份、权限管控与操作规范,才能在误操作发生时从容应对,将损失降到最低。如果遇到特殊场景(如 Binlog 丢失、备份损坏),欢迎留言交流,共同探讨解决方案!

专注Java和MySQL领域知识分享 2245

嵌入式开发也玩“全家桶”?手把手教你用CLion+PyOCD调试APM32,比OpenOCD更简单

本文详细介绍了如何使用CLion和PyOCD组合进行APM32嵌入式开发,提供从环境配置到实战调试的完整指南。相比传统工具如Keil和OpenOCD,这套方案更轻量、易用,特别适合现代开发者需求,涵盖CMake配置、PyOCD调试技巧及常见问题解决。

weixin_42543046的博客 464

如何快速恢复误删数据?掌握binlog2sql,MySQL数据恢复的终极解决方案

在数据库管理中,误删或误更新数据是常见的紧急情况,传统恢复方法往往耗时且影响业务运行。**binlog2sql**作为一款强大的MySQL数据恢复工具,能够直接解析binlog日志并生成回滚SQL,帮助开发者和DBA在几分钟内完成数据恢复,避免因数据丢失导致的业务中断。本文将详细介绍binlog2sql的核心功能、安装步骤、实战案例及使用技巧,让你轻松掌握这一必备技能。 ## 为什么选择binl

gitblog_00100的博客 951

【AI生成】市面上主流自组网厂家的技术及市场研究

经过对全球自组网产业技术特征与市场格局的系统分析,本文得出以下核心结论:技术演进呈现智能化与融合化双轨路径 当前自组网技术创新已突破传统组网架构局限,形成"协议优化-架构创新-场景适配"的递进式发展路径。国际厂商聚焦智能算法应用,如Silvus采用深度学习实现动态拓扑优化,传输时延较传统方案降低37%;国内企业则侧重异构网络融合,中国移动设计院提出的5G LAN架构使工业场景通信可靠性提升至99.99%。

qq_31310977的博客 1696

工业相机的检测原理课件(建议收藏)

本课件为各位工程师详细介绍了工业相机的视觉检测原理 ,旨在为工程师调试工业相机的视觉检测原理时提供理论性指导。

Bamboo265925的博客 498

mysql误删误操作恢复数据,比传统方式和binlog2sql更快速用的恢复方式-reverse_sql恢复数据(单表多表)

2. 通过reverse_sql 如下命令:delete 为例(其他误操作 update 、insert 等误操作需要-op 的值不一样,可以看 ./reverse_sql -h 参数说明)场景: 误操作删除了某个表的数据,本文只讲工具的使用,首先自己通过mysqlbinlog或者记录找到误操作的时间范围:开始时间和结束时间,下面以误删为例。打开如下图的txt文件内容,有操作时间点 、操作的原生sql、及根据原生sql生成的回滚sql。提取并过滤出真正需要回滚sql 执行 就能恢复了。

boomLJiE的博客 900

CDR插件开发之CPG插件017 - 在VS2019中实现CPG插件调试(自动写入CPG、自动启动CDR)

在上篇文章中,讲解了图像导出实例:当文档打开后,自动导出当前页面的图像到系统临时文件夹。在代码编写过程中,导出图像路径变量tmpFileName 被修改了很多次,有没有办法实现调试功能,通过控制台打印变量,而不用编译成CPG后再通过消息框来调试?当然是可以的。本篇作为单独篇,以CDR X8版本为例,讲解CPG插件在VS2019中实现调试的具体方法。 工程搭建准备 按照惯例,本篇文章的序号为017,请直接拷贝上一个工程016-export-image(拷贝前最好清理掉 Debug、x64等编译目录..

Zebe 1811

3步掌握MySQL binlog2sql:从日志解析到数据恢复的完整指南

- 问题反馈:通过GitHub Issues提交问题 - 贡献代码:欢迎提交Pull Request改进功能 ## 🎉 结语 binlog2sql作为一款优秀的MySQL日志解析工具,将复杂的二进制日志转换为直观的SQL语句,大大简化了数据恢复和审计工作。通过本文的指南,你应该能够: 1. 正确安装和配置binlog2sql 2. 掌握基础解析和闪回功能 3. 在实际场景中应用数据恢复 4

gitblog_00457的博客 1088

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

SQL 执行失败如何回滚?事务已提交还能恢复吗?——MySQL 误操作数据恢复全指南

摘要:本文系统解析了MySQL数据误操作后的恢复策略。关键点包括:未提交事务可通过Undo Log回滚;已提交事务需依赖Binlog恢复(ROW格式最佳);Redo Log仅用于崩溃恢复。实战部分演示了如何解析Binlog定位误操作并生成恢复脚本。最佳实践建议开启Binlog、定期备份、限制高危权限、SQL审核等。核心结论:未提交靠Undo Log,已提交靠Binlog,Redo Log仅保障数据持久性。没有Binlog的数据库一旦误操作将难以恢复。

慢慢 1162

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

误删mysql某表数据,通过binlog2sql工具数据恢复

1.导读 binlog2sql是大众点评开源的一款用于解析binlog的工具,在测试环境试用了下,还不错。DBA或开发人员,有时会误删或者误更新数据,如果是线上环境并且影响较大,就需要能快速回滚。传统恢复方法是利用备份重搭实例,再应用去除错误sql后的binlog来恢复数据。此法费时费力,甚至需要停机维护,并不适合快速回滚。也有团队利用LVM快照来缩短恢复时间,但快照的缺点是会影响mysql的性能。现在有不少好用而且效率又高的开源闪回工具如binlog2sql、mysqlbinlog_flashback,这

User_bie的博客 814

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

高效binlog解析工具:my2sql数据恢复与分析实战指南

在数据库运维工作中,误操作导致的数据丢失、主从同步异常等问题时有发生。传统的binlog(二进制日志)解析工具往往操作复杂、学习成本高,难以快速解决实际问题。而my2sql作为一款轻量级binlog解析工具,通过简洁的命令行操作即可实现数据恢复、操作审计等核心功能,成为数据库管理员和开发人员的得力助手。 ## 一、数据运维的痛点与my2sql的核心价值 数据库操作的不可逆性使得每一个误删、误改

gitblog_01151的博客 1107

MySQL数据恢复终极指南:my2sql与binlog2sql对比测试

在数据库管理领域,数据恢复是保障业务连续性的关键环节。Archery作为一款强大的MySQL数据库管理Web工具,集成了多种数据恢复方案,其中my2sql和binlog2sql是两种常用的binlog解析工具。本文将深入对比这两款工具的功能特性、使用场景及实战效果,帮助数据库管理员快速掌握高效的数据恢复技巧。 ## 📌 核心功能解析 ### my2sql:新一代binlog解析工具 my2s

gitblog_00432的博客 1175

MySQL误删数据别慌!5分钟学会用Binlog快速恢复(附实战命令)

本文详细介绍了MySQL数据库误删数据后的紧急恢复实战指南。通过解析Binlog二进制日志,文章重点讲解了基于时间点恢复和位置点恢复等高级恢复技术,并提供了具体的实战命令与操作步骤,帮助开发者在黄金五分钟内快速、精准地找回丢失的数据,构建有效的应急响应体系。

s8t9u0v1w的博客 457

从MySQL误操作到秒级恢复:binlog2sql实战指南

在数据库运维和开发工作中,数据误操作是每个DBA和开发人员都可能面临的噩梦。一次错误的DELETE、UPDATE操作可能导致业务中断、数据丢失,甚至引发严重的生产事故。传统的恢复方法需要从备份还原、应用binlog,过程复杂耗时,而MySQL自带的mysqlbinlog工具输出格式复杂,难以直接使用。binlog2sql应运而生,为MySQL数据库提供了一种高效、精准的数据恢复解决方案。 ##

gitblog_01052的博客 158

mysql利用binlog数据恢复

今天我给大家分享一下binlog数据恢复的几种方法。如果你是数据库管理员,相信通过这节课,可以帮助你快速进行数据恢复。当然其他职业的同学,也能一定程度上了解到数据的价值,以及恢复的套路。 要谈数据恢复问题,先不得不说一下数据的重要性。可以说,一个企业最核心的就是数据了,我一个老师曾说,不管你什么架构,一切都是为数据服务的,数据是一个企业最核心的价值。不过出现问题的话,数据一旦被删除,每过一秒,都将对企业造成巨大的损失。最近,还真的发生了一起删库跑路事件,微盟7*24小时紧急恢复数据,商家...

u011657179的博客 801
上一篇: GreatSQL优化技巧:使用 FUNCTION 代替标量子查询
下一篇: CTE查询数据量过大导致MySQL 8.0发生CORE问题解析
GreatSQL社区
博客等级 码龄5年 1210粉丝 390原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值