gtid通过为每个事务生成唯一server_uuid:sequence_number并检查gtid_executed集合来防止重复执行;启用master_auto_position=1后主库只推送从库缺失的gtid事务;--set-gtid-purged=on是dump硬性要求,enforce_gtid_consistency=on是启动前提。

开启GTID后,主从切换不再依赖人工计算 binlog 文件名和 position,自动跳过已执行事务,避免因误算、日志轮转或 relay log 清理导致的数据丢失或重复应用。
GTID 如何防止事务重复执行
每个事务在提交时生成唯一 server_uuid:sequence_number,写入 binlog 的 Gtid_log_event。从库 SQL 线程执行前会检查 gtid_executed 集合:若该 GTID 已存在,直接跳过;否则才执行并记录到自身 binlog(即使 log_slave_updates=OFF,也强制维护 gtid_executed)。这从根本上杜绝了“同一个事务在从库执行两次”的风险。
常见错误现象:
- 传统复制中手动
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000012', MASTER_LOG_POS=4567,但实际该 position 已被 purge 或 relay log 被重置,导致跳过部分事务 - 主库故障后,DBA 根据
SHOW MASTER STATUS找新主库的起始点,却忽略了从库可能已执行了部分后续事务,强行拉起后出现主键冲突或数据覆盖
MASTER_AUTO_POSITION=1 是怎么工作的
启用后,从库连接主库时主动发送自己的 gtid_executed 集合,主库比对后只推送缺失的 GTID 事务——整个过程不涉及文件名、position、甚至不需要主库开启 log_slave_updates(MySQL 5.7+)。
必须注意的实操要点:
-
CHANGE MASTER TO必须显式指定MASTER_AUTO_POSITION=1,不能省略或设为0 - 从库
gtid_mode必须为ON,且gtid_executed不能包含与待同步主库冲突的 GTID(例如导入 dump 时用了--set-gtid-purged=OFF) - 主库无需额外配置,只要自身
gtid_mode=ON且事务已落 binlog 即可响应请求
为什么 --set-gtid-purged=ON 是 dump 的硬性要求
mysqldump 加上该参数后,会在 SQL 文件开头插入类似 SET @@GLOBAL.GTID_PURGED='a1b2c3d4-...:1-100'; 的语句。导入前,从库必须满足:
-
gtid_mode=ON已生效 -
RESET SLAVE ALL已执行(RESET SLAVE不清空gtid_purged,会冲突) - 从未执行过任何事务(否则
gtid_executed与 dump 中的GTID_PURGED不兼容)
反例:--set-gtid-purged=OFF 导出的 dump,导入后从库认为 “自己没执行过任何 GTID 事务”,后续 START SLAVE 必然报错 ERROR 3021 (HY000): This server is not configured as a replication slave 或无法协商位置。
enforce_gtid_consistency=ON 不是可选项,是启动前提
不设这个参数,SET GLOBAL gtid_mode = ON 会直接报错:ERROR 1782 (HY000): You must set enforce_gtid_consistency=ON before enabling GTID mode。
它真正拦截的是这些操作:
-
CREATE TABLE ... SELECT(非原子,可能部分写入) -
CREATE TEMPORARY TABLE(临时表不记 binlog,GTID 无法追踪) - 跨引擎事务(如 InnoDB + MyISAM 混合更新)
最容易被忽略的一点:该参数必须在所有节点上先设为 ON,再逐个升级 gtid_mode;如果只在主库设了,从库仍为 OFF,复制过程中遇到被拦截语句,就会卡住并报错。











