是,mysql(innodb)在rollback瞬间立即释放事务持有的所有锁,包括行锁、间隙锁、临键锁、意向锁等,锁生命周期严格绑定事务生命周期;auto-inc锁和lock tables加的表锁为例外。

事务回滚时锁是否立即释放?
会,MySQL(InnoDB)在执行 ROLLBACK 的**瞬间**就释放该事务持有的所有锁——包括行锁、间隙锁、临键锁、表级意向锁,甚至临时表锁。这不是“稍后清理”,而是同步清除 lock_sys 中的锁登记项,整个过程原子且不可中断。
为什么不能等“事务结束”再释放?
如果锁等到事务真正退出才释放,就可能造成锁残留或悬挂状态,尤其在连接异常断开、客户端崩溃、或超时 kill 后未显式 rollback 的场景下,锁会卡住其他事务,引发连锁阻塞。InnoDB 的设计原则是:**锁的生命周期严格绑定事务生命周期,事务终止即锁释放**。
- 显式
ROLLBACK→ 立即释放全部锁 - 隐式回滚(如连接中断、语句报错且未捕获)→ MySQL 主动触发回滚并同步释放锁
-
COMMIT→ 同样立即释放锁(但此时数据已持久化)
哪些锁“例外”不走这个规则?
绝大多数锁都遵循上述规则,但有一个关键例外:AUTO-INC 锁。它不是事务锁,而是表级轻量锁,用于保证自增列分配的连续性;它在 INSERT 语句执行完就立刻释放,**与事务是否提交/回滚无关**。这也是为什么高并发插入时,即使事务回滚了,自增值也不会回退。
另外注意:某些显式加的表锁(如 LOCK TABLES ... WRITE)不属于事务锁体系,它们不受 ROLLBACK 影响,必须用 UNLOCK TABLES 手动释放——这类锁已基本被 InnoDB 行锁取代,日常开发中应避免使用。
实操中容易踩的坑
开发者常误以为“只要没 COMMIT,锁就一直占着”,从而在应用层做长事务或手动 sleep 等待,结果导致锁堆积、死锁频发。真实情况是:
- 事务空闲等待期间,锁照常持有,其他事务会被阻塞(尤其是写锁)
- 哪怕只执行了一条
SELECT ... FOR UPDATE就停住,锁也一直不放,直到 rollback 或 commit - Spring 声明式事务中,若 service 方法抛出未被捕获的运行时异常,框架会自动 rollback → 锁也会随之释放;但如果 catch 了异常又没 re-throw,事务可能意外提交或挂起,锁行为变得不可控
最稳妥的做法:事务粒度尽量短,读写分离清晰,避免在事务中调用外部服务或执行耗时操作——锁不是资源池里的可复用对象,它是排他性的“占用凭证”,越早交出,系统越顺畅。










