会释放,但不是立刻无条件释放——ROLLBACK执行完成时,事务持有的所有行锁、表锁(含意向锁)才统一清理;锁生命周期严格绑定事务,事务结束即释放。

事务回滚时锁是否释放?
会释放,但不是“立刻无条件释放”——ROLLBACK 执行完成的那一刻,该事务持有的所有行锁、表锁(含意向锁)才会被统一清理。这是 InnoDB 的硬性规则:锁的生命周期严格绑定事务生命周期,事务结束(无论 COMMIT 还是 ROLLBACK),锁就释放。
为什么有时感觉“回滚后还卡着”?
常见错觉来源有三个:
- 你执行了
ROLLBACK,但没确认事务真正结束了——比如客户端连接没关闭、autocommit=0 且后续没显式开启新事务,导致会话仍处于“隐式事务未提交”状态; - 锁被其他**未结束的事务**持有,和你的回滚无关。例如事务 A 正在等事务 B 释放某行锁,B 回滚了,A 却因自身逻辑卡住没继续执行,看起来像“锁还在”;
- 在
READ-COMMITTED或READ-UNCOMMITTED隔离级别下,InnoDB 对不匹配WHERE条件的扫描行会**提前释放行锁**,但这和回滚无关,是查询过程中的动态释放行为。
不同隔离级别对锁释放时间有影响吗?
有,但只影响“加锁期间”的行为,不影响回滚时刻的释放逻辑:
-
REPEATABLE-READ和SERIALIZABLE:所有加的行锁/表锁,一律等到事务结束(COMMIT或ROLLBACK)才释放; -
READ-COMMITTED:普通SELECT不加锁(快照读),但UPDATE/DELETE仍加行锁,且只锁住最终命中的记录(不匹配的扫描行会边扫边放); -
READ-UNCOMMITTED:几乎不加锁,自然也谈不上“回滚释放”——但这个级别极少用于生产。
注意:ROLLBACK 本身不会改变锁的释放时机,它只是“触发事务结束”的动作之一。
如何验证锁是否真被释放了?
别靠猜,用 MySQL 自带视图查:
- 查当前阻塞关系:
SELECT * FROM information_schema.INNODB_TRX;
看trx_state是否为ROLLING BACK或已消失; - 查锁等待链:
SELECT * FROM information_schema.INNODB_LOCK_WAITS;
如果为空,说明没有活跃等待; - 查锁本身:
SELECT * FROM performance_schema.data_locks;
(MySQL 8.0+)或老版本用SHOW ENGINE INNODB STATUS\G中的TRANSACTIONS部分。
最容易被忽略的是:锁释放不等于事务彻底退出。如果应用层没关闭连接、或者用了连接池且连接被复用,旧事务上下文可能残留——务必确认 INNODB_TRX 中对应 trx_id 已消失,才算真正干净。










