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

8次阅读

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

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

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

mysql 的行级锁(如 select ... for UPDATEUPDATE 加的锁)在 COMMITROLLBACK 执行完毕后**立即释放**。这是 InnoDB 的默认行为,也是 ACID 中隔离性的基础保障。

但要注意:如果事务中包含隐式或显式的 LOCK TABLES(MyISAM 风格),这类表级锁不会随事务提交释放,必须显式执行 UNLOCK TABLES;InnoDB 一般不走这条路,除非手动切换存储引擎或误用。

  • 使用 information_schema.INNODB_TRXINNODB_LOCKS(MySQL 5.6/5.7)或 performance_schema.data_locks(8.0+)可查当前持有锁
  • 长事务会持续持锁,哪怕只读未修改——只要用了 SELECT ... FOR UPDATESELECT ... 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 STATUSGTRANSACTIONS 部分,注意 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 卡住了。

text=ZqhQzanResources