MySQL事务默认不自动开启,AUTOCOMMIT=1使每条DML立即提交;需BEGIN/START TRANSACTION或SET AUTOCOMMIT=0显式开启事务,且事务从第一条DML开始生效,DDL会隐式提交当前事务。
MySQL 的 AUTOCOMMIT 默认为 1(开启),这意味着每条单独的 DML 语句(如 INSERT、UPDATE、DELETE)都会立即提交,不处于事务中。只有当你执行 BEGIN、START TRANSACTION 或设置 AUTOCOMMIT=0 后,后续语句才进入同一个事务上下文。
BEGIN 和 START TRANSACTION 本身不修改数据,只是标记事务边界起点;真正让事务“活起来”的是第一条可写操作。例如:
START TRANSACTION; SELECT @x := 1; -- 不影响事务状态(纯查询,无锁、不计入事务) INSERT INTO t VALUES (1); -- 此刻事务才真正持有行锁、写入 undo log UPDATE t SET a=2 WHERE id=1; -- 属于同一事务
注意:SELECT 在默认隔离级别下是快照读,不触发事务锁,除非加 FOR UPDATE 或 LOCK IN SHARE MODE。
以下语句在 AUTOCOMMIT=1 下会**自动开启并立即提交**一个隐式事务(仅限支持事务的引擎,如 InnoDB):
INSERT、UPDATE、DELETE
CREATE TABLE ... SELECTDROP TABLE、ALTER TABLE(部分操作)但这些都不是“可回滚的多语句事务”——它们各自独立,无法用 ROLLBACK 撤销前面已执行的语句。比如:
INSERT INTO t VALUES (1); UPDATE t SET a=2; -- 即使没写 COMMIT,这两条也已各自提交
想跨语句回滚,必须先关 AUTOCOMMIT 或用 START TRANSACTION 包裹。
事务内语句按客户端发送顺序执行,但其他事务能否看到中间结果,由隔离级别决定:
READ UNCOMMITTED:其他事务能立刻看到未提交修改(脏读)READ COMMITTED:每次 SELECT 都读取最新已提交快照REPEATABLE READ(InnoDB 默认):事务第一次 SELECT 建立快照,后续读都复用SERIALIZABLE:所有 SELECT 隐式加锁,
强制串行关键点:事务顺序 ≠ 提交顺序。两个并发事务可能因锁等待、死锁检测等原因,实际提交顺序与执行顺序不一致。
最容易被忽略的是:DDL 语句(如 ALTER TABLE)在 InnoDB 中会隐式提交当前事务,哪怕它出现在 START TRANSACTION 之后。这意味着你不能在事务中安全地混合 DDL 和 DML 并指望整体回滚。