事务回滚时锁是否释放?
会释放,但不是“立刻无条件释放”——
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已消失,才算真正干净。
