ROLLBACK失效主因是autocommit=1、引擎非InnoDB、跨连接或DDL隐式提交;须先查@@autocommit、SHOW CREATE TABLE确认前提,再用START TRANSACTION和纯DML操作保障事务完整性。

事务回滚失效:先确认 autocommit 是否关闭
MySQL 默认 autocommit=1,每条语句执行完立刻提交,ROLLBACK 对它完全无效。这是“部分语句已生效”最常见原因。
- 用
SELECT @@autocommit;查当前值,返回1就说明开着 - 显式关闭:在事务开始前执行
SET autocommit = 0;(注意:不是SET autocommit = OFF) - 更稳妥的做法是统一用
START TRANSACTION;开启——它会自动临时关闭 autocommit,且不受会话级设置干扰
存储引擎不支持事务:InnoDB 是硬性前提
哪怕 autocommit 关了、BEGIN 也写了,如果表用的是 MyISAM 引擎,ROLLBACK 依然不会撤回任何数据。
- 查引擎:
SHOW CREATE TABLE 表名;或SELECT ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA='db_name' AND TABLE_NAME='table_name'; - 改引擎:
ALTER TABLE 表名 ENGINE=InnoDB;(注意:大表需锁表,生产环境慎操作) - 新建表务必显式指定:
CREATE TABLE ... ENGINE=InnoDB;,别依赖旧版本默认行为
跨连接或隐式提交导致事务断裂
事务只在单个数据库连接内有效。一旦连接断开、或执行了 DDL(如 CREATE TABLE、ALTER TABLE),MySQL 会自动触发 COMMIT,后续 ROLLBACK 只能回滚该次连接中 DDL 之后的操作。
- DDL 操作无法回滚,遇到就只能拆事务:把 DDL 单独拎出来,在事务外执行
- 应用层要确保所有 SQL 都走同一个连接对象(比如 PHP 的
$pdo实例不能复用后被销毁再重建) - 长事务容易被超时中断(
wait_timeout),可在执行前加SET SESSION wait_timeout = 300;延长,但不建议设过大
需要局部回滚?SAVEPOINT 是唯一可控方案
当事务里某几步失败,但前面的逻辑必须保留(比如日志已写、状态已更新),就不能靠 ROLLBACK 全局撤销,得用保存点。
- 设点:
SAVEPOINT sp_after_log;(命名不能重复,否则覆盖) - 出错后:
ROLLBACK TO SAVEPOINT sp_after_log;,只撤回该点之后的语句 - 注意:
RELEASE SAVEPOINT sp_after_log;不影响回滚能力,但释放后不能再用这个名字 - DDL 仍会清空所有保存点,所以保存点必须放在纯 DML 区块内


















