精准跳过GTID事务需三步:STOP SLAVE → SET GTID_NEXT='xxx:nnn' → BEGIN; COMMIT;必须确认该事务可丢弃,否则引发数据不一致,且不可用sql_slave_skip_counter。

跳过一个报错的GTID事务:先确认位置再注入空事务
MySQL复制中断在GTID模式下,常见错误是 Could not execute Write_rows event on table 或 Slave has retried X times,根本原因是主从间某个事务无法执行,但又不能跳过整个relay log——必须精准跳过那个GTID。
关键不是“怎么跳”,而是“跳之前必须确认它确实该跳”:比如该事务在从库已存在、或主库上早已被回滚、或业务侧确认可丢弃。盲目跳过会引发数据不一致。
- 先查报错时的GTID:
SHOW SLAVE STATUS\G,看Retrieved_Gtid_Set和Executed_Gtid_Set的差集,再结合Seconds_Behind_Master: NULL和SQL_Delay: 0确认卡点 - 用
SELECT * FROM performance_schema.replication_applier_status_by_coordinator;查当前正在重放哪个GTID - 别直接
SET GTID_NEXT—— 必须先STOP SLAVE,且确保slave_parallel_workers = 0(否则多线程下GTID_NEXT行为不可控)
SET gtid_next = 'xxx-yyy-zzz:123' 后必须立刻提交
SET GTID_NEXT 不是配置项,而是一次性会话级指令,它的作用只是“告诉MySQL:接下来这条语句,强制打上这个GTID”。它本身不产生事务,也不改变复制状态——你得手动补一条空事务让它落地。
漏掉 COMMIT 是最常踩的坑:设完 GTID_NEXT 就 START SLAVE,结果MySQL发现没有对应事务,直接报错 ERROR 1840 (HY000): @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty 或卡死在 Waiting for master to send event。
- 正确顺序只有三步:
STOP SLAVE→SET GTID_NEXT = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee:123';→BEGIN; COMMIT; -
BEGIN; COMMIT;是必须的,CREATE TABLE t1(id INT); DROP TABLE t1;这类操作也行,但别用 DDL(某些版本对DDL的GTID处理有边界问题) - 设完立刻
SELECT @@GTID_NEXT;确认值没被自动重置(比如误连了其他会话)
注入空事务后,Executed_Gtid_Set 不会自动更新?
注入成功后,SHOW SLAVE STATUS\G 里的 Executed_Gtid_Set 看起来没变,这是正常现象。MySQL只在真正执行relay log里的事务时才更新它;你手工注入的事务属于“外部写入”,不会触发复制状态机的自动推进。
真正要看的是:SELECT GTID_SUBTRACT('aaa-bbb-ccc:1-123', @@global.gtid_executed); 返回空集合,说明该GTID已被包含;同时 START SLAVE 后不再报那个GTID的错,才代表跳过生效。
- 别依赖
Executed_Gtid_Set字符串长度或末尾数字判断是否成功 - 如果跳过后仍报错,大概率是
GTID_NEXT值写错了(比如少了一位、用了小写uuid、冒号前后空格)——GTID校验严格,错一位就完全不匹配 - 5.7.20+ 和 8.0.22+ 对
GTID_NEXT的合法性检查更严,非法格式会直接拒绝设置,而不是静默失败
为什么不用 sql_slave_skip_counter?
因为开了GTID就不能用 sql_slave_skip_counter。MySQL会直接报错:ERROR 1794 (HY000): The slave is configured with MASTER_AUTO_POSITION = 1, but the master does not support GTID-based replication(即使主库支持,只要启用了 MASTER_AUTO_POSITION,这个变量就被禁用)。
本质是设计取舍:GTID要求“每个事务全球唯一可追溯”,跳过机制必须基于GTID本身,而非偏移量。想绕开只能临时关GTID(停主从、改配置、重启),但代价远高于注入空事务,且风险极高。
- 不要试图在GTID模式下
SET GLOBAL sql_slave_skip_counter = 1—— 它会静默失效,或者触发不可预知的复制断裂 - 如果经常要跳事务,说明上游写入不规范(比如主库执行了非事务引擎表操作、或用了
CREATE TEMPORARY TABLE),该修的是源头,不是反复跳 - 8.0.23+ 支持
STOP REPLICA UNTIL SQL_BEFORE_GTIDS = '...',但仍是辅助手段,不能替代精准注入
真正麻烦的从来不是那几条命令,而是确认“这个GTID到底能不能跳”——日志里没记录、业务没留痕、开发说“应该没问题”,这种时候注入空事务就是把不确定变成确定的错误。










