MySQL事务需先设autocommit=0再BEGIN(等价于START TRANSACTION),否则ROLLBACK无效;不支持嵌套事务,仅能用SAVEPOINT实现部分回滚;COMMIT/ROLLBACK后事务结束,后续操作需重新开启。

MySQL 中的 BEGIN、COMMIT 和 ROLLBACK 是手动控制事务的核心语句,但它们**不保证自动开启事务**——是否真正进入事务状态,取决于当前会话的 autocommit 设置。
autocommit 关闭才是事务生效的前提
MySQL 默认开启 autocommit=1,此时每条 DML 语句(如 INSERT、UPDATE)都会立即提交,BEGIN 后执行的语句仍可能被自动提交,导致 ROLLBACK 失效。
- 必须先执行
SET autocommit = 0,再用BEGIN(或START TRANSACTION)显式开启事务 -
BEGIN本身不是 SQL 标准关键字,在 MySQL 中是START TRANSACTION的同义词,但不带任何隐式设置作用 - 某些客户端(如 phpMyAdmin、MySQL Workbench)可能默认关闭
autocommit,但脚本或连接池中往往不会,不能依赖
COMMIT 和 ROLLBACK 的边界很明确
事务从 BEGIN(或 START TRANSACTION)开始,到 COMMIT 或 ROLLBACK 结束。之后的语句不属于该事务,也不会被回滚。
-
COMMIT后,所有修改永久写入磁盘(受存储引擎和刷盘策略影响),无法撤销 -
ROLLBACK仅能回滚当前未提交事务中的修改;如果中间执行过COMMIT,之前已提交的部分不可逆 - 执行
ROLLBACK后,事务结束,后续语句需重新BEGIN才能再次开启事务
嵌套事务在 MySQL 中不存在
MySQL 不支持真正的嵌套事务。BEGIN 后再写一个 BEGIN,不会创建子事务,而是被忽略或报错(取决于版本和 SQL 模式)。
- 想实现“部分回滚”,只能靠
SAVEPOINT:例如SAVEPOINT sp1、ROLLBACK TO sp1 -
SAVEPOINT不会结束事务,ROLLBACK TO后仍可继续COMMIT或ROLLBACK - 注意
SAVEPOINT名称不能重复,否则后一次会覆盖前一次
常见误用场景与示例
下面这段代码在 autocommit=1 下运行,ROLLBACK 实际无效:
SET autocommit = 1;
BEGIN;
INSERT INTO users(name) VALUES('Alice');
ROLLBACK;正确写法应为:
SET autocommit = 0;
BEGIN;
INSERT INTO users(name) VALUES('Alice');
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;或者更稳妥地,用标准语法并显式控制:
SET autocommit = 0;
START TRANSACTION;
INSERT INTO users(name) VALUES('Bob');
DELETE FROM logs WHERE created_at < NOW() - INTERVAL 7 DAY;
COMMIT;最容易被忽略的是:应用层连接(如 Python 的 pymysql、Java 的 Connection)通常默认开启 autocommit,且事务状态不跨请求保持——每次 HTTP 请求都得自己重置 autocommit 并管理 BEGIN/COMMIT/ROLLBACK。










