Navicat同步任务本身不主动加锁,但因目标表缺失主键或唯一索引、并发线程过高、WHERE条件无索引、中断后残留事务未回滚及双向同步范围重叠等错配,极易触发InnoDB行锁竞争与死锁闭环。

Navicat 自动化同步任务本身不主动加锁或构造死锁,但它生成的 SQL 在目标库执行时,极易触发 InnoDB 的行锁竞争和事务等待闭环——根本原因在于同步逻辑与数据库加锁机制的错配,而非 Navicat “做了什么”,而是它“没控制住什么”。
同步过程中目标表缺失主键或唯一索引
Navicat 在比对和写入阶段依赖主键(或 UNIQUE NOT NULL 索引)快速定位记录。若目标表无主键,它会退化为全表扫描 + 逐行 SELECT 判断是否存在,再决定 INSERT 还是 UPDATE:
- 每条
SELECT ... WHERE col = ?都可能走全表扫描,持锁时间拉长,增加与其他事务交叉概率 -
INSERT ... ON DUPLICATE KEY UPDATE失效(无唯一约束),Navicat 可能改用REPLACE INTO或先DELETE后INSERT,引发间隙锁(Gap Lock)和临键锁(Next-Key Lock)冲突 - 实测中,无主键表同步时
SHOW ENGINE INNODB STATUS常见WAITING FOR THIS LOCK TO BE GRANTED与LOCK WAIT交替出现
并发线程数过高 + 未分段导致热点行争抢
Navicat「高级」设置里的线程数不是“越快越好”,而是直接放大目标库的锁队列压力:
- 设为 4 线程以上时,多个线程可能同时尝试更新同一主键范围(如
id BETWEEN 10000 AND 20000),InnoDB 对相同索引记录加 X 锁,形成等待链 - 若同步使用
WHERE updated_at > ?且该字段无索引,所有线程都扫全表,大量事务在相同页上申请 S 锁 → 升级为 X 锁时互相阻塞 -
SHOW PROCESSLIST中频繁看到状态为Updating、Locked或Sending data(实为锁等待),CPU 不高但innodb_row_lock_waits持续上涨
同步任务中断后残留事务未回滚
自动化任务常被定时脚本调起,若执行中源库断连、目标库超时或本地机器休眠,Navicat 进程退出但目标库事务未显式提交/回滚:
- 残留事务仍持有行锁、间隙锁,甚至 MDL 锁(尤其涉及
ALTER TABLE类结构同步时) -
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX可查到TRX_STATE = 'RUNNING'且TRX_STARTED早于当前时间 10 分钟以上 - 对应
TRX_MYSQL_THREAD_ID在INFORMATION_SCHEMA.PROCESSLIST中已消失,即“幽灵事务”,必须KILL其线程 ID 才能释放锁
双向同步误操作引发主键覆盖与锁升级
所谓“双向同步”在 Navicat 中只是两次独立单向任务,若未严格隔离写入范围,极易造成自增主键冲突或时间戳倒挂:
- A→B 同步后,B 表某行
id=1001被更新;B→A 同步时若未加WHERE updated_at > ?条件,会把 B 的新值又写回 A,而 A 此刻可能正有事务在更新同一行 → 死锁检测触发 - 跨实例同步时,两边自增初始值重叠(如都从 1 开始),
INSERT报Duplicate entry '1001' for key 'PRIMARY',Navicat 默认重试逻辑会反复尝试,持续申请锁 - 更隐蔽的是:Navicat 在冲突时可能悄悄改用
UPDATE ... WHERE id = ? AND version = ?,若version字段无索引,每次判断都触发全表扫描+锁升级
真正卡住的从来不是 Navicat 界面,而是目标库中那些看不见的锁等待链——它们藏在 INNODB_TRX 和 INNODB_LOCK_WAITS 里,只在你查 SHOW ENGINE INNODB STATUS 的那一刻才暴露全貌。同步前确认主键、压低线程数、禁用 Delete、人工清理残留事务,比调任何 Navicat 设置都管用。


















