Navicat数据同步死锁主因是MDL锁争用而非隔离级别,需优先清理SHOW PROCESSLIST中状态异常进程、长事务及备份/优化操作,KILL干扰进程比调整READ COMMITTED更有效。
Navicat 数据同步时为什么设成 READ COMMITTED 还会死锁
设成 read committed 本身不解决死锁,它只是降低事务间可见性冲突的概率;真正触发死锁的往往是 ddl(如 alter table)与 dml(如 update)在元数据锁(mdl)层面的争夺,和事务隔离级别无关。mysql 的 mdl 锁在任何隔离级别下都会被 ddl 强制申请,且不兼容正在执行的 dml 事务——哪怕那个 dml 只读、只查、甚至只用了 select ... for update。
同步前必须检查的三个锁源
Navicat 同步卡住,90% 不是事务隔离级别问题,而是以下三类锁未清理:
-
SHOW PROCESSLIST里 status 为Sending data、Locked或Waiting for table metadata lock的进程——这些才是真凶,不是你同步窗口里的事务 - 源库或目标库存在未提交的长事务:
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), TRX_STARTED)) > 60; - 目标表上有正在运行的备份、分析或
OPTIMIZE TABLE操作,它们也会持有 MDL 写锁
KILL 掉干扰进程比调隔离级别更直接有效
别花时间改 Navicat 同步设置里的 “Transaction Isolation Level”,那个选项只影响同步脚本内部的 SELECT/INSERT 语句,对 DDL 和外部并发事务完全无效。实操步骤就两步:
- 在 Navicat 查询窗口执行:
SHOW PROCESSLIST;,找出所有涉及目标库、目标表、且状态异常的ID - 挨个执行:
KILL 12345;(把12345换成上一步看到的 ID),注意不要 KILL 自己当前连接的 ID(看User列和Host列区分) - 确认无残留后,再点同步——比调隔离级别快 10 倍,也更可靠
真正该调的不是隔离级别,而是同步策略
如果你频繁在同步时撞上死锁,说明同步方式有问题。重点调整这几个地方:
- 关闭
Resolve dependencies automatically(如果源库对象依赖混乱,自动解析反而会制造交叉等待) - 同步前手动执行:
SET SESSION lock_wait_timeout = 3;,让阻塞的 DDL 快速失败而非死等 - 避开业务高峰执行同步;若必须在线,用
pt-online-schema-change替代 Navicat 原生同步——它靠影子表+触发器绕过 MDL 锁
隔离级别是数据可见性的开关,不是锁调度的开关。死锁发生在锁申请顺序上,不是读取逻辑上。


















