mysql事务提交后锁什么时候释放_mysql执行顺序说明

来源:这里教程网 时间:2026-02-28 20:47:05 作者:

事务提交后行锁立刻释放,但表锁可能延迟

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
(仅限部分操作)
锁释放本身很快,慢的往往是别人在等你释放之后的那一瞬间——而那一瞬间,可能已经被另一个没看清执行计划的 SQL 卡住了。

相关推荐