跳过多个GTID事务必须用SET GTID_PURGED,不能靠循环SET GTID_NEXT;后者仅适用于单点精准跳过,且须严格按STOP SLAVE→SET SESSION GTID_NEXT→BEGIN; COMMIT;三步执行。

跳过多个GTID事务不能只靠SET GTID_NEXT
直接用SET GTID_NEXT循环设置、提交空事务来跳过多个GTID,看似可行,实际会失败。因为GTID_NEXT是会话级一次性指令,每次设完必须立刻执行一个事务(BEGIN; COMMIT;),且该事务会被记录进gtid_executed——但MySQL不会自动推进复制位点,你跳一个、再跳一个,中间若没重置或误连会话,@@SESSION.GTID_NEXT可能已变回AUTOMATIC,后续SET就无效。更关键的是:多事务跳过本质是“跳过一段GTID区间”,而GTID_NEXT只处理单点,强行套用效率低、易出错、不可审计。
真正能跳过多个GTID的只有SET GTID_PURGED
要跳过连续或离散的多个GTID(比如uuid1:100-105, uuid2:200, uuid3:50-52),必须用SET GTID_PURGED,但它有硬性前提:
- 从库必须已
STOP SLAVE,且RESET SLAVE ALL(清空relay log和复制元数据) -
@@GLOBAL.GTID_EXECUTED必须为空(即从库尚未执行任何GTID事务)——这通常只在全新从库或刚重置后成立 - 操作前需手动构造目标GTID集合,例如:
SELECT GTID_SUBTRACT('uuid1:1-105,uuid2:1-200', 'uuid1:1-99,uuid2:1-199');确认差集就是你想跳过的部分 - 执行时必须用
SET GLOBAL GTID_PURGED = 'uuid1:100-105,uuid2:200,uuid3:50-52';,注意这是全局操作,且只能设一次(设过后不能再改)
一旦设了GTID_PURGED,这些GTID就被MySQL认定为“已在本实例执行过”,后续拉取主库binlog时会自动过滤掉它们。
SET GTID_NEXT只适合单点精准跳过,且顺序不能错
当复制卡在某个明确GTID(如aaaa-bbbb-cccc-dddd:123)报错时,GTID_NEXT才是正解。但必须严格按三步走:
-
STOP SLAVE;—— 必须停,否则并发线程下行为不可控 -
SET SESSION GTID_NEXT = 'aaaa-bbbb-cccc-dddd:123';—— 注意是SESSION,不是GLOBAL;设完立刻SELECT @@SESSION.GTID_NEXT;确认值生效 -
BEGIN; COMMIT;—— 不能省BEGIN,否则COMMIT在read_only=ON从库上会报ERROR 1632;也不要用DDL(如CREATE TABLE),某些MySQL 5.7小版本对DDL+GTID组合有bug
漏掉任一环,比如设完不COMMIT、或COMMIT后没重置GTID_NEXT就START SLAVE,轻则复制卡死,重则触发ERROR 1840要求清空gtid_executed。
最容易被忽略的验证动作:别只看Executed_Gtid_Set
注入空事务后,SHOW SLAVE STATUS\G里的Executed_Gtid_Set看起来没变——这正常。它只反映relay log里执行的事务,不包含你手工注入的。真要确认是否跳过成功,得用:
SELECT GTID_SUBTRACT('aaaa-bbbb-cccc-dddd:123', @@global.gtid_executed);
如果返回空集合(''),说明该GTID已被纳入执行集合;如果还返回aaaa-bbbb-cccc-dddd:123,说明注入失败,得检查是否BEGIN; COMMIT;真的执行了、有没有被其他会话覆盖GTID_NEXT、或者从库启用了enforce_gtid_consistency=OFF(此时GTID机制本身已退化)。


















