事务提交后行锁立即释放,但表锁(如LOCK TABLES)需显式UNLOCK;InnoDB行锁释放与ACID一致,而MDL锁独立于事务,DDL会因活跃事务阻塞。

事务提交后行锁立刻释放,但表锁可能延迟
MySQL 的行级锁(如 SELECT ... FOR UPDATE 或 UPDATE 加的锁)在 COMMIT 或 ROLLBACK 执行完毕后**立即释放**。这是 InnoDB 的默认行为,也是 ACID 中隔离性的基础保障。
但要注意:如果事务中包含隐式或显式的 LOCK TABLES(MyISAM 风格),这类表级锁不会随事务提交释放,必须显式执行 UNLOCK TABLES;InnoDB 一般不走这条路,除非手动切换存储引擎或误用。
- 使用
information_schema.INNODB_TRX和INNODB_LOCKS(MySQL 5.6/5.7)或performance_schema.data_locks(8.0+)可查当前持有锁 - 长事务会持续持锁,哪怕只读未修改——只要用了
SELECT ... FOR UPDATE或SELECT ... LOCK IN SHARE MODE -
AUTOCOMMIT=0下,一个语句不自动提交,锁会一直挂着,直到你敲COMMIT
MySQL 语句执行顺序不是“从上到下”,而是按优化器重排 + 锁获取时机决定
你写的 SQL 顺序 ≠ 实际执行顺序。MySQL 优化器会基于索引、统计信息、成本估算重排执行计划,而加锁动作发生在执行器真正访问某行时,不是解析时。
例如:
UPDATE t1 SET a = 1 WHERE id IN (SELECT id FROM t2 WHERE status = 'pending');表面看是先查
t2 再更新 t1,但实际可能是先锁定 t1 匹配行(甚至全表扫描加锁),再回表查 t2 过滤——取决于是否能走索引、是否启用 semi-join 优化等。
-
EXPLAIN FORMAT=TREE(8.0+)或EXPLAIN ANALYZE能看到真实执行路径和锁范围 -
WHERE条件没走索引?很可能升级为临键锁(Next-Key Lock),锁住间隙,影响并发插入 - 子查询里带
FOR UPDATE?外层 UPDATE 可能被阻塞,因为子查询先持锁,且锁不会提前释放
唯一索引冲突导致的锁等待,常被误认为“提交后还卡着”
这不是锁没释放,而是下一个事务在尝试获取锁时被阻塞了。比如事务 A 插入 (id=100) 并提交,事务 B 紧接着插入相同 id,B 会卡在 INSERT 阶段,直到 A 提交完成并释放意向锁 —— 但 B 看到的现象是“A 提交后我还在等”,其实是 B 自己在等锁获取机会。
- 查
performance_schema.events_statements_current可确认 B 是否卡在insert状态 - 查
sys.innodb_lock_waits(封装视图)能直接看到谁在等谁、等什么锁 - 用
SHOW ENGINE INNODB STATUS\G看TRANSACTIONS部分,注意lock struct(s)和waiting for this lock to be granted
DDL 操作(如 ALTER TABLE)会触发元数据锁(MDL),与事务提交无关
很多人发现“刚 COMMIT 完,另一个 ALTER 就卡住了”,以为是事务锁没放干净。其实 DDL 加的是 MDL,它独立于事务生命周期,只要还有活跃事务访问该表(哪怕只是 SELECT),ALTER 就必须等所有事务结束才能获取排他 MDL。
-
SELECT不提交也占着 MDL 读锁,所以长查询会让 DDL 无限等待 - MySQL 5.7+ 可设
lock_wait_timeout控制 DDL 等待上限,避免雪崩 - 线上改表务必避开业务高峰,优先用
pt-online-schema-change或 8.0 的ALGORITHM=INSTANT(仅限部分操作)










