因为GTID复制要求事务标识唯一,注入空事务可将出错GTID手动加入GTID_EXECUTED集合,使SQL线程“以为已执行”而跳过该事务;需严格按stop slave→set gtid_next→begin;commit;→set gtid_next=automatic→start slave执行。

为什么 set gtid_next + 空事务能跳过 GTID 错误
因为 GTID 复制要求每个事务必须有唯一、不可重复的标识,而从库 SQL 线程在执行时会检查 GTID_EXECUTED 集合——如果目标 GTID 已存在,就跳过;如果不存在且无法执行(比如删不存在的行),就会报错停住。注入空事务的本质是:手动把出错的 GTID 加入 GTID_EXECUTED,让后续同步逻辑“以为它已执行”,从而绕过该事务。
set gtid_next 的实操要点和常见翻车点
执行前必须确认当前从库没有正在运行的复制线程,否则 gtid_next 设置无效或被覆盖:
-
stop slave;后立刻查show slave status\G,确认Slave_SQL_Running: No -
gtid_next是 SESSION 级变量,只对当前连接生效,不能在另一个窗口里 set 再 commit - 必须用
begin; commit;(不能用start transaction;,部分 MySQL 版本不识别) - 事务号格式必须严格匹配错误中出现的 GTID,例如
'ab1b2733-2401-11e7-82fc-525400abbf4b:50',多一个空格或少一位都会失败 - 执行完
commit后,务必执行SET SESSION GTID_NEXT = 'AUTOMATIC';,否则后续任何写操作都可能被卡住
跳过之后 start slave 还报错?先看这三项
空事务只是“标记跳过”,不解决底层数据不一致。如果紧接着又报新错误(比如 Last_Error: Can't find record in 'xxx' 或 Last_Errno: 1146),说明问题没根除:
- 检查
Executed_Gtid_Set是否真的包含了刚注入的 GTID(show master status和show slave status\G对比) - 确认主库上该 GTID 对应的 binlog 还没被 purge——查
SELECT @@gtid_purged;,若结果里不含该 GTID,说明主库日志已丢,空事务跳过只是临时掩盖 - 若错误变成表不存在(
errno: 1146)或库删除失败(errno: 1010),说明 DDL 已失序,空事务无济于事,得重建从库或人工补对象
什么时候不该用空事务,而该重置复制关系
空事务只适用于单点事务冲突,一旦出现以下情况,强行跳过会导致主从数据持续漂移:
- 错误 GTID 所在事务之前还有多个未执行的 GTID(
Retrieved_Gtid_Set明显大于Executed_Gtid_Set),说明 relay log 已断层 - 主库
gtid_purged包含的范围超出了从库当前Executed_Gtid_Set,此时change master to master_auto_position=1必然触发error 1236 - 从库
GTID_EXECUTED被人为清空过(如执行过reset master),再注入空事务会污染全局 GTID 状态
这些情况下,真正安全的做法是导出主库数据重新初始化从库,并确保 mysqldump 带 --set-gtid-purged=ON 参数,否则新从库的 GTID_PURGED 会为空,后续无法对接主库 GTID 流水。


















