根本原因是表被其他事务长期持有写锁,navicat默认连接不控制锁等待;需查innodb_trx和innodb_lock_waits定位锁源,避免盲目kill,外键约束需手动先删后建。
navicat 16 执行 alter table 卡住或报错 “lock wait timeout exceeded” 的根本原因,是目标表正被其他事务长期持有写锁,而 navicat 默认连接不控制锁等待行为——不是工具坏了,是它在等一个迟迟不释放的锁。
查 INNODB_TRX 和 INNODB_LOCK_WAITS 定位真实锁源
Navicat 界面里点“保存”改字段,背后执行的是普通 ALTER TABLE,它会申请 MDL(metadata lock)和表级/行级 InnoDB 锁。一旦有长事务没提交,它就卡住。别猜,直接查:
- 先看谁在跑太久:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW()) - TIME_TO_SEC(TRX_STARTED) > 60;—— 关注TRX_ID、TRX_MYSQL_THREAD_ID、TRX_QUERY - 再看谁在等谁:
SELECT * FROM information_schema.INNODB_LOCK_WAITS;—— 输出里BLOCKING_TRX_ID对应的就是锁源 - 注意:
TRX_STATE = 'RUNNING'不代表安全,可能是空闲事务(idle in transaction),照样持锁
别急着 KILL,先确认事务业务语义
查到线程 ID 后,用 KILL [thread_id] 能解锁,但风险极高:
- 如果该事务正在执行订单导入、账务核对等关键操作,KILL 会导致数据不一致或应用报错回滚失败
- 某些 ORM 框架(如 Django + transaction.atomic)可能隐式开启长事务,需结合应用日志交叉验证
- 更稳妥的做法是联系对应服务负责人,确认能否主动提交或回滚;若不可控,再考虑 KILL,并同步通知监控告警
临时缓解:调高会话级超时参数
治标不治本,但能避免频繁断连重试:
- 在 Navicat 查询窗口顶部菜单 →「查询」→「新建查询」,先执行:
SET SESSION innodb_lock_wait_timeout = 300; - 如果还报
ERROR 2013 (HY000): Lost connection to MySQL server during query,说明是网络层超时,补上:SET SESSION net_write_timeout = 7200; - 注意:这些只对当前会话生效,关闭窗口即失效;不要在连接属性里全局设高值,否则掩盖真实锁问题
外键约束导致的 “Cannot change column” 报错要单独处理
哪怕你只是改个 VARCHAR(50) 到 VARCHAR(100),只要该列参与了外键定义(无论是作为主键被引用,还是作为外键列),MySQL 严格模式就会拒绝:
- 先查外键名:
SELECT CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'child_table' AND COLUMN_NAME = 'xxx'; - 删外键:
ALTER TABLE `child_table` DROP FOREIGN KEY `fk_name`; - 再改字段:
ALTER TABLE `parent_table` MODIFY COLUMN `xxx` VARCHAR(100); - 最后重建外键(注意
ON DELETE和字段类型必须完全一致,否则 Navicat 同步模型时会丢约束)
Navicat 的「设计表」界面不会自动生成这些前置/后置语句,它只翻译你界面上的操作,这点极易忽略。











