从库报1062错误而主库不报,因主库用INSERT IGNORE等忽略冲突,从库却严格重放binlog导致重复插入;常见原因包括REPLACE INTO、主从切换异常或从库误写。

为什么从库会报 1062 错误,但主库没这事?
因为主库写入时可能靠应用层去重、或用 INSERT IGNORE/ON DUPLICATE KEY UPDATE 吞掉冲突,而从库是严格按 binlog 重放——如果主库某条语句实际没插入(被 ignore 掉),但从库的 relay log 里它还是“执行了一条 INSERT”,而此时从库本地已有同主键/唯一键的记录,就直接炸出 1062 Duplicate entry。
常见诱因:主库用 REPLACE INTO 或 INSERT ... SELECT 没加条件判断;主从切换后 GTID 或 position 跳过部分事件,导致从库状态和主库不一致;或者人为在从库写了数据(哪怕只读也挡不住误操作)。
跳过错误前必须确认的三件事
盲目执行 SET GLOBAL sql_slave_skip_counter = 1 或 START SLAVE SKIP_COUNTER = 1 很危险——你跳过的可能不是一条孤立 INSERT,而是整个事务链的起点。
- 先查
SHOW SLAVE STATUS\G,确认Seconds_Behind_Master是不是 0,Slave_SQL_Running_State是否卡在 “executing statement” - 看
Exec_Master_Log_Pos和Relay_Master_Log_File,用mysqlbinlog解析对应 binlog 文件,定位那条报错的 SQL 到底干了啥:mysqlbinlog --base64-output=decode-rows -v mysql-bin.000001 | grep -A 10 -B 5 "your_table_name"
- 检查该表在从库是否真有冲突行:
SELECT * FROM your_table WHERE id = X,再对比主库同条件结果——别假设“主库有,从库就该有”
清理冲突数据的两种安全做法
目标不是让复制跑起来,而是让从库数据和主库最终一致。跳过只是临时止痛,删/改才是根治。
- 如果冲突是单条主键重复,且确定从库多出的数据无业务价值:
DELETE FROM your_table WHERE id = X,再START SLAVE - 如果从库缺数据(比如主库 INSERT 成功,从库因之前错误漏掉了),不能只删,得补:
INSERT INTO your_table SELECT * FROM your_table ON MASTER WHERE id = X——但注意,这需要先关掉read_only,且确保不会触发其他唯一约束 - 更稳妥的方式:用
pt-table-sync对比并修复差异,命令形如:pt-table-sync --sync-to-master h=slave_host,u=user,p=pass,D=dbname,t=tablename
,它会自动生成修复语句,但务必加--print先预览
为什么 sql_slave_skip_counter 在 GTID 模式下根本不能用
启用了 GTID(gtid_mode = ON)后,MySQL 不允许用 sql_slave_skip_counter,否则会报错 ERROR 1794 (HY000): The slave is configured with a different GTID set than the master。
此时只能用 SET GTID_NEXT 注入空事务:
- 执行
STOP SLAVE -
SET GTID_NEXT = 'xxx:yyy'(值来自SHOW SLAVE STATUS的Retrieved_Gtid_Set中缺失的那个 GTID) BEGIN; COMMIT;SET GTID_NEXT = 'AUTOMATIC'START SLAVE
这个过程极易填错 GTID 导致复制彻底断裂,建议只在明确知道跳过哪个事务 ID 时才动手。
真正麻烦的从来不是怎么跳过 1062,而是怎么确认那条冲突语句背后有没有隐藏的外键级联、触发器副作用、或者上游业务逻辑依赖。一旦从库数据偏离主库,光修一条记录没用,得顺着 binlog 往前翻几条,看看事务边界在哪。


















