主从复制中事务不一致的典型表现
主库写入成功但从库报
ERROR 1032 (HY000): Can't find record in table或
ERROR 1062 (23000): Duplicate entry,基本可判定事务在从库回放时出错。这不是网络中断或延迟问题,而是事务上下文在 binlog 中未被完整保留——比如用了非事务引擎(
MyISAM)、混合了 DML 和 DDL、或启用了
binlog_format=STATEMENT但函数含不确定性(如
NOW()、
UUID())。
必须用 ROW 格式 + 事务引擎
binlog_format=ROW是 MySQL 主从事务同步的底线要求,它把每行变更的实际值写入 binlog,绕过 SQL 重放逻辑,避免函数不确定性导致的主从差异。同时,所有参与复制的表必须使用
InnoDB(不能是
MyISAM),否则事务原子性无法保障,
BEGIN...COMMIT范围内的多语句可能只部分同步到从库。 检查当前格式:
SELECT @@binlog_format;,非
ROW需在主从两端配置文件中统一设为
binlog_format = ROW并重启 确认表引擎:
SHOW CREATE TABLE t1;,发现
ENGINE=MyISAM必须转为
ENGINE=InnoDB禁止在事务中混用 DDL(如
ALTER TABLE),DDL 在 ROW 模式下会隐式提交事务,破坏原子边界
跳过错误不是修复,而是临时止损
当从库已出现事务冲突(如主库插入后从库该行已被删),
SET GLOBAL sql_slave_skip_counter = 1可跳过当前事件,但仅适用于单条语句级错误;对事务级错误(如一个
INSERT ... SELECT批量插入失败),更稳妥的是用
gtid_next跳过整个 GTID 事务:
STOP SLAVE; SET GTID_NEXT='aabbccdd-eeff-1111-2222-333344445555:12345'; BEGIN; COMMIT; SET GTID_NEXT='AUTOMATIC'; START SLAVE;
注意:跳过前务必确认该事务在从库确实无业务影响,且主库没后续依赖此事务的更新;跳过操作不可逆,事后需人工比对数据一致性。
GTID 模式下事务同步更可靠但有约束
启用
gtid_mode=ON后,每个事务有唯一标识,从库能自动定位同步位点,避免传统
relay_log_file+
relay_log_pos手动定位出错。但它强制要求所有实例都开启 GTID,且禁止执行
CREATE TABLE ... SELECT、
CREATE TEMPORARY TABLE等不支持 GTID 的语句——这些语句在 GTID 模式下会直接报错
ERROR 1786 (HY000): Statement violates GTID consistency。 迁移前先检查:
SELECT * FROM information_schema.INNODB_TRX;确保无长事务阻塞 从库切换 GTID 前需先停复制、重置
RESET SLAVE ALL,再启动时指定
START SLAVE UNTIL SQL_AFTER_GTIDS控制回放范围 GTID 不解决应用层逻辑冲突(如主从同时更新同一行),只保证“相同事务”被准确传递和执行
真正难处理的从来不是复制链路本身,而是事务里藏着的隐式依赖、跨库操作、或者应用误把从库当主库写入——这些不会报错,但会让数据偏移在数小时后才暴露。
