3.gtid
GTID(全局事务标识符)是 MySQL 给每个事务发的唯一身份证号,用于主从复制和基于 binlog 的数据恢复。
核心组成
GTID = 服务器UUID : 事务序号
示例:9e1669b5-2a59-11f1-a260-000c295e8e85:1-7
└───────── UUID ─────────┘ └─┘
服务器唯一标识 第7个事务
主要用途
| 场景 | 说明 |
|---|---|
| 主从复制 | 从库根据 GTID 自动知道哪些事务已执行,不会重复 |
| 故障恢复 | 从 binlog 中提取指定范围的事务进行恢复 |
| 数据追踪 | 通过 GTID 精确定位每个事务 |
3.1开启GTID服务
bash
mysql> show variables like '%gtid%';
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | OFF | #
| gtid_executed | |
| gtid_executed_compression_period | 0 |
| gtid_mode | OFF | #
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
enforce_gtid_consistency 和 gtid_mode 要为ON
bash
[root@bogon ~]# vim /etc/my.cnf
[root@bogon ~]# tail -4 /etc/my.cnf
log_bin=mysql-bin
binlog_format=ROW
gtid_mode=ON
enforce-gtid-consistency=ON
[root@bogon mysql]# systemctl start mysqld
mysql> show variables like '%gtid%';
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed | |
| gtid_executed_compression_period | 0 |
| gtid_mode | ON |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
3.2创建数据
bash
mysql> show binary log status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 158 | | | |
+------------------+----------+--------------+------------------+-------------------+
#关于数据库db3
mysql> create database db3;
Query OK, 1 row affected (0.01 sec)
mysql> show binary log status;
+------------------+----------+--------------+------------------+----------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+----------------------------------------+
| mysql-bin.000001 | 340 | | | 9e1669b5-2a59-11f1-a260-000c295e8e85:1 |
+------------------+----------+--------------+------------------+----------------------------------------+
1 row in set (0.00 sec)
#关于数据库gtid
mysql> create database gtid;
Query OK, 1 row affected (0.01 sec)
mysql> use gtid;
Database changed
mysql>
mysql> create table t1(id int);
Query OK, 0 rows affected (0.02 sec)
mysql> show binary log status;
+------------------+----------+--------------+------------------+------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+------------------------------------------+
| mysql-bin.000001 | 713 | | | 9e1669b5-2a59-11f1-a260-000c295e8e85:1-3 |
+------------------+----------+--------------+------------------+------------------------------------------+
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t1 values(1);
Query OK, 1 row affected (0.00 sec)
mysql> insert into t1 values(2);
Query OK, 1 row affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
mysql> show binary log status;
+------------------+----------+--------------+------------------+------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+------------------------------------------+
| mysql-bin.000001 | 1074 | | | 9e1669b5-2a59-11f1-a260-000c295e8e85:1-4 |
+------------------+----------+--------------+------------------+------------------------------------------+
mysql> SHOW BINLOG EVENTS IN 'mysql-bin.000001';
+------------------+------+----------------+-----------+-------------+-------------------------------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+------+----------------+-----------+-------------+-------------------------------------------------------------------+
| mysql-bin.000001 | 4 | Format_desc | 1 | 127 | Server ver: 8.4.8, Binlog ver: 4 |
| mysql-bin.000001 | 127 | Previous_gtids | 1 | 158 | |
| mysql-bin.000001 | 158 | Gtid | 1 | 235 | SET @@SESSION.GTID_NEXT= '9e1669b5-2a59-11f1-a260-000c295e8e85:1' |
| mysql-bin.000001 | 235 | Query | 1 | 340 | create database db3 /* xid=6 */ |
| mysql-bin.000001 | 340 | Gtid | 1 | 417 | SET @@SESSION.GTID_NEXT= '9e1669b5-2a59-11f1-a260-000c295e8e85:2' |
| mysql-bin.000001 | 417 | Query | 1 | 525 | create database gtid /* xid=8 */ |
| mysql-bin.000001 | 525 | Gtid | 1 | 602 | SET @@SESSION.GTID_NEXT= '9e1669b5-2a59-11f1-a260-000c295e8e85:3' |
| mysql-bin.000001 | 602 | Query | 1 | 713 | use `gtid`; create table t1(id int) /* xid=13 */ |
| mysql-bin.000001 | 713 | Gtid | 1 | 792 | SET @@SESSION.GTID_NEXT= '9e1669b5-2a59-11f1-a260-000c295e8e85:4' |
| mysql-bin.000001 | 792 | Query | 1 | 867 | BEGIN |
| mysql-bin.000001 | 867 | Table_map | 1 | 915 | table_id: 92 (gtid.t1) |
| mysql-bin.000001 | 915 | Write_rows | 1 | 955 | table_id: 92 flags: STMT_END_F |
| mysql-bin.000001 | 955 | Table_map | 1 | 1003 | table_id: 92 (gtid.t1) |
| mysql-bin.000001 | 1003 | Write_rows | 1 | 1043 | table_id: 92 flags: STMT_END_F |
| mysql-bin.000001 | 1043 | Xid | 1 | 1074 | COMMIT /* xid=16 */ |
+------------------+------+----------------+-----------+-------------+-------------------------------------------------------------------+
mysql> create table t2(id int);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t2 values (2);
Query OK, 1 row affected (0.00 sec)
mysql> insert into t2 values (3);
Query OK, 1 row affected (0.00 sec)
mysql> flush logs;
Query OK, 0 rows affected (0.01 sec)
mysql> show binary log status;
+------------------+----------+--------------+------------------+------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+------------------------------------------+
| mysql-bin.000002 | 198 | | | 9e1669b5-2a59-11f1-a260-000c295e8e85:1-7 |
+------------------+----------+--------------+------------------+------------------------------------------+
主要关注File 和 Executed_Gtid_Set 这个部分
eg.
File:mysql-bin.000002
Executed_Gtid_Set:9e1669b5-2a59-11f1-a260-000c295e8e85:1-7
mysql-bin.000002是二进制日志文件编号
9e1669b5-2a59-11f1-a260-000c295e8e85这台 MySQL 的唯一身份证号
这里的1-7表示:这个 MySQL 上已经执行了 7 个 GTID 事务,编号从 1 到 7
3.3模拟数据破坏
bash
mysql> drop database gtid;
Query OK, 2 rows affected (0.03 sec)
mysql> drop database gtid;
Query OK, 2 rows affected (0.03 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| db3 |
| information_schema |
| mydb |
| mysql |
| performance_schema |
| school |
| sys |
+--------------------+
7 rows in set (0.00 sec)
3.4还原数据 & 检验
1.确定gtid
2.确定要++还原的数据++的 gtid事务 的起始和结束编号。
3.涉及到的日志文件
上一步是删除了gtid数据库。。。所以还原这个部分gtid:9e1669b5-2a59-11f1-a260-000c295e8e85
该数据库的gtid事务 的起始和结束编号:2-7
涉及到的日志文件:mysql-bin.000001和mysql-bin.000002
bash
[root@bogon ~]# cd /var/lib/mysql
#这个是2-7
[root@bogon mysql]# mysqlbinlog --include-gtids='9e1669b5-2a59-11f1-a260-000c295e8e85:2-7' mysql-bin.000001 mysql-bin.000002 -r /tmp/gtid2.sql
#这个1-7错误(包含了db3,而db3还存在),用来测试的
[root@bogon mysql]# mysqlbinlog --include-gtids='9e1669b5-2a59-11f1-a260-000c295e8e85:1-7' mysql-bin.000001 mysql-bin.000002 -r /tmp/gtid1.sql
#--skip-gtids参数
[root@bogon mysql]# mysqlbinlog --skip-gtids --include-gtids='9e1669b5-2a59-11f1-a260-000c295e8e85:1-7' mysql-bin.000001 mysql-bin.000002 -r /tmp/gtid3.sql
bash
#用gtid1.sql
mysql> set sql_log_bin=0;
Query OK, 0 rows affected (0.00 sec)
mysql> source /tmp/gtid1.sql;
mysql> set sql_log_bin=1;
Query OK, 0 rows affected (0.00 sec)
mysql> show databases like 'gtid';
Empty set (0.00 sec)
#用gtid2.sql
mysql> set sql_log_bin=0;
Query OK, 0 rows affected (0.00 sec)
mysql> source /tmp/gtid2.sql;
mysql> set sql_log_bin=1;
Query OK, 0 rows affected (0.00 sec)
mysql> show databases like 'gtid';
Empty set (0.00 sec)
#用gtid3.sql
mysql> set sql_log_bin=0;
Query OK, 0 rows affected (0.00 sec)
mysql> source /tmp/gtid3.sql;
mysql> set sql_log_bin=1;
Query OK, 0 rows affected (0.00 sec)
mysql> show databases like 'gtid';
+-----------------+
| Database (gtid) |
+-----------------+
| gtid |
+-----------------+
mysql> select * from gtid.t2;
+------+
| id |
+------+
| 2 |
| 3 |
+------+
Q:why用用gtid2.sql不行???
删除后,创建 gtid 库和表数据相当于"没执行过",应该能重放
但 GTID 机制不这么认为,它只管"有没有执行过",不管"结果还在不在"。
所以恢复时必须用 --skip-gtids 撕掉标签,强制重放。
这不是 GTID 没用,而是它本来就不是为"误删恢复"这个场景设计的。
不加
--skip-gtids:MySQL 一看 GTID 编号已经执行过,直接跳过,不恢复。
加--skip-gtids:把 GTID 编号撕掉,MySQL 当作新事务,正常执行恢复。
你的实验对应关系
| 文件 | 加没加 --skip-gtids |
结果 | 原因 |
|---|---|---|---|
| gtid1.sql | ❌ 没加 | 失败 | GTID 1-7 全被跳过 |
| gtid2.sql | ❌ 没加 | 失败 | GTID 2-7 全被跳过 |
| gtid3.sql | ✅ 加了 | 成功 | GTID 被移除,正常执行 |
记住这一条规则
从 binlog 恢复误删数据时,永远加
--skip-gtids
GTID幂等性
GTID 幂等性是给主从复制设计的,防止重复执行;误删恢复时一定要加 --skip-gtids,绕过幂等性检查。
MySQL 有一个系统变量
gtid_executed,记录着所有已经执行过的 GTID 编号。当一个事务进来时:
- MySQL 检查它的 GTID 编号
- 去
gtid_executed里查找- 找到了 → 直接跳过(保证不重复执行)
- 没找到 → 正常执行
这就是幂等性的来源:同一个 GTID 的事务,执行多次和一次的效果一样(不会重复执行)