mysql事务在什么时候开启_mysql执行流程解析

9次阅读

事务默认在每条DML语句执行时瞬间开启并立即提交(autocommit=1),显式开启需SET autocommit=0或BEGIN/START TRANSACTION,实际事务活性始于第一条DML执行。

mysql事务在什么时候开启_mysql执行流程解析

事务默认什么时候开启?别被“自动提交”骗了

mysql 中事务不是你一连上就自动“开着”的,而是由 autocommit 状态决定的。默认情况下,autocommit=1,这意味着每条 INSERTUPDATEdelete 语句都会被当作一个独立事务——执行完立刻提交,根本没机会回滚。

  • 所以严格来说:**没有显式开启事务时,事务是“瞬间开启又瞬间结束”的**,你感觉不到它的存在
  • 只有当你关闭自动提交(SET autocommit = 0)或显式执行 BEGIN / START TRANSACTION 后,事务才真正“活”起来,进入可控制的生命周期
  • 注意:select 不会触发事务(除非加了 for UPDATELOCK IN SHARE MODE),它只是快照读,不改变事务状态

显式开启事务的两种写法,效果一样但习惯不同

BEGINSTART TRANSACTION 都能开启一个新事务,它们在 InnoDB 中完全等价,没有底层差异,选哪个纯看团队规范或个人偏好。

  • BEGIN 更简洁,适合快速交互式调试(比如 MySQL CLI 里随手测试)
  • START TRANSACTION 语义更清晰,明确表达“我要开始一个事务”,更适合生产 SQL 脚本或 ORM 日志中追踪
  • ⚠️ 别用 BEGIN WORK —— 虽然语法合法,但已过时,官方文档不推荐
START TRANSACTION; UPDATE account SET balance = balance - 100 WHERE id = 1; INSERT INTO log (msg) VALUES ('deducted 100'); COMMIT;

事务真正的“起点”不在 BEGIN,而在第一条修改语句执行时

InnoDB 的事务生命周期其实比 SQL 语句更底层:当你执行 START TRANSACTION,MySQL 只是分配了事务 ID、初始化 undo log 空间;真正让事务“动起来”的,是第一条 DML(如 UPDATE)执行时——此时才会生成第一个 undo log 记录,并锁定对应行/间隙。

  • 如果 START TRANSACTION 后只执行 SELECT,事务处于“空闲但活跃”状态,不产生 undo log,也不加锁(默认 RR 隔离级别下仍是快照读)
  • 一旦执行首个 UPDATE,InnoDB 才真正开始维护事务一致性,后续所有操作都受该事务上下文约束
  • 这意味着:事务的“实际开启点”是数据变更动作,不是语法关键字——这对理解死锁和锁等待特别关键

容易被忽略的关键细节:BEGIN 之前的状态也影响事务行为

很多人以为 BEGIN 是事务一切的起点,其实不然。事务行为还取决于它之前的会话设置,尤其是隔离级别和 autocommit 状态。

  • SET TRANSACTION ISOLATION LEVEL READ COMMITTED 必须在 BEGIN 之前执行才生效;如果写在 BEGIN 之后,会报错或被忽略(取决于 MySQL 版本)
  • 如果当前会话 autocommit=1,你执行 BEGIN 后没 COMMIT 就断开连接,MySQL 会自动回滚未提交的更改——但这个“自动回滚”不是事务本身的行为,而是连接终止时的清理机制
  • 最隐蔽的坑:某些客户端(如 phpMyAdmin、DBeaver)会在每次执行 SQL 后自动加 COMMIT,即使你写了 BEGIN,也可能被悄悄提交掉,务必检查客户端配置里的“自动提交”开关

事务真正可控的起点,是你关掉 autocommit 或敲下 BEGIN 的那一刻;但它的“呼吸感”——何时加锁、何时记日志、何时影响并发——全藏在第一条 DML 执行的瞬间。别只盯着语法,得看 InnoDB 实际做了什么。

text=ZqhQzanResources