LOCK TABLES 一用就卡住,因其是全局表级锁且隐式关闭自动提交,未手动 UNLOCK TABLES 会导致后续所有 DML(含 SELECT)阻塞;InnoDB 下多无效或报错,仅 MyISAM 有实际意义。
MySQL 中 LOCK TABLES 为什么一用就卡住?
因为 lock tables 是全局表级锁,且会隐式断开当前会话的自动提交模式——一旦你没手动 unlock tables,后续所有 dml(哪怕只是 select)都会被阻塞,连自己都卡住。
- 只在 MyISAM 表上有实际意义;InnoDB 下多数场景会被降级为无效操作或报错(尤其开启
innodb_table_locks=OFF时) - 执行后,当前连接进入“非事务模式”,
START TRANSACTION或BEGIN不再开启新事务,COMMIT/ROLLBACK也无效 - 如果连接异常断开(比如超时、客户端崩溃),锁不会自动释放,得靠 DBA 手动
UNLOCK TABLES或杀掉连接
替代 LOCK TABLES 的 InnoDB 安全写法
InnoDB 原生支持行级锁和事务,真需要并发控制时,优先用 SELECT ... FOR UPDATE 或 SELECT ... LOCK IN SHARE MODE,它们只锁命中行,不阻塞无关读写。
-
SELECT * FROM orders WHERE id = 123 FOR UPDATE:加排他锁,其他事务不能读写该行,直到本事务结束 - 必须在
BEGIN/START TRANSACTION内执行,否则锁在语句结束后立即释放 - 避免在长事务里持锁太久;WHERE 条件没走索引 → 锁升级为表锁,效果等同
LOCK TABLES - 注意死锁风险:
UPDATE t1 SET x=1 WHERE id=1; UPDATE t2 SET y=1 WHERE id=2;和反向顺序组合容易触发
LOCK TABLES 还能用在哪些真实场景?
仅限极少数运维/备份场景,比如做 MyISAM 表的冷备份,或迁移前临时禁止写入。业务代码里几乎不该出现。
- 备份前:先
FLUSH TABLES WITH READ LOCK(比LOCK TABLES ... READ更安全,会阻塞所有写并刷盘) - 恢复后务必配对执行
UNLOCK TABLES,别依赖连接关闭——连接池复用时锁还在 - 不要对视图或临时表执行
LOCK TABLES,MySQL 会报错ERROR 1109 (42S02): Unknown table - 权限检查严格:需要
LOCK TABLES+SELECT权限,仅SELECT权限不够
并发高时用错锁机制的典型症状
现象不是“报错”,而是“慢”和“卡死”:应用日志里大量请求超时,SHOW PROCESSLIST 看到一堆 Waiting for table level lock 或 Locked 状态。
- 查锁源:
SELECT * FROM performance_schema.metadata_locks WHERE OBJECT_TYPE='TABLE'; - 看谁在等:
SELECT * FROM information_schema.INNODB_TRX;+INNODB_LOCK_WAITS关联分析 - MyISAM 表上执行
INSERT DELAYED会绕过表锁,但已废弃,5.6+ 不支持 - PHP 的
mysqli默认不自动 commit,LOCK TABLES后忘UNLOCK就等于永久锁表
真正难处理的不是语法怎么写,是锁的生命周期和事务边界的匹配——一个 LOCK TABLES 操作背后,往往暴露的是整个数据访问层对隔离级别的误用。

















