rollback仅能回滚当前连接中显式开启且未提交的innodb事务中的dml操作;需确认in_transaction=1、autocommit=0、无隐式提交及表引擎为innodb。

不能“撤销所有误操作”,只能回滚当前连接中显式开启、尚未提交的 InnoDB 事务里的 DML 修改。 一旦 COMMIT 执行,或语句在 autocommit=1 模式下单独执行完毕,就彻底不可逆。
确认当前是否处于可回滚的活跃事务中
很多人执行 ROLLBACK 后发现数据没变回去,根本原因是:压根没有事务在运行。必须逐项验证:
- 运行
SELECT @@in_transaction;—— 返回1才表示有未提交事务 - 运行
SELECT @@autocommit;—— 返回0是手动事务模式;若为1,则每条语句已自动提交,ROLLBACK无效 - 检查是否已执行过
COMMIT或隐式提交(比如中间执行了ALTER TABLE、DROP TABLE、CREATE INDEX等 DDL) - 确认操作的表是
InnoDB引擎:SHOW CREATE TABLE `table_name`查看ENGINE=InnoDB;MyISAM表不支持事务
ROLLBACK 前必须显式开启事务
ROLLBACK 不是全局撤销命令,它只对当前事务生效,而事务必须由 START TRANSACTION 显式启动。常见错误是直接写 SQL 然后想回滚:
UPDATE users SET name = 'test' WHERE id = 1; ROLLBACK; -- ❌ 无效:autocommit=1 下这条 UPDATE 已提交
正确做法是:
SET autocommit = 0; -- 可选,但推荐显式控制 START TRANSACTION; UPDATE users SET name = 'test' WHERE id = 1; DELETE FROM logs WHERE created_at <p>注意:<code>START TRANSACTION</code> 和 <code>BEGIN</code> 等价,但 <code>BEGIN</code> 在某些存储过程上下文中可能被解析为语句块开始,建议统一用 <code>START TRANSACTION</code> 避免歧义。</p><h3>需要部分回滚时必须用 SAVEPOINT</h3><p><code>ROLLBACK</code> 默认回滚整个事务,无法只撤某一步。需要分段控制时,必须用 <code>SAVEPOINT</code>:</p><pre class="brush:php;toolbar:false;">START TRANSACTION; INSERT INTO orders VALUES (1001, 'pending'); SAVEPOINT after_insert; UPDATE inventory SET stock = stock - 1 WHERE item_id = 123; -- 发现库存更新错了,但想保留订单插入 ROLLBACK TO SAVEPOINT after_insert; COMMIT;
要点:
-
SAVEPOINT名字不能重复,否则后定义的会覆盖前一个 -
ROLLBACK TO SAVEPOINT不会结束事务,后续仍可继续操作或最终COMMIT/ROLLBACK -
SAVEPOINT仅在当前事务内有效,连接断开即失效
最容易被忽略的一点:事务的生命周期完全绑定在客户端连接上。连接异常中断(如网络断开、客户端崩溃),未提交事务会自动回滚——但这不是“保护机制”,而是 MySQL 的兜底行为;真正可控的撤销,只发生在你还在连接中、且明确知道事务状态的前提下。











