事务未显式开启时rollback无效;必须先执行begin/start transaction开启事务,再执行dml,否则autocommit=1导致语句立即提交,无法回滚。

事务没显式开启,ROLLBACK 就没用
直接执行 UPDATE 或 DELETE 后发现写错了,再敲 ROLLBACK —— 大概率报错或毫无反应。因为默认 autocommit=1,语句一执行就永久生效了,根本不在事务里。
必须先显式开启事务才能回滚:
-
BEGIN、BEGIN TRANSACTION或START TRANSACTION(三者等价,MySQL/PostgreSQL/SQL Server 都支持) - 不能只靠
SET autocommit = 0:它只是关自动提交,但不等于“当前就在事务中”;得再执行一条 DML(如SELECT 1)才会真正进入事务状态(MySQL 行为) - ORM(如 Django、SQLAlchemy)可能隐式开事务,但 raw SQL 不会,别假设框架替你兜底
异常发生时,ROLLBACK 不会自动触发
执行 UPDATE users SET name = 'x' WHERE id = 999; 报错(比如主键冲突、外键失败),数据库不会自动回滚整个事务——除非你提前设置了 SET XACT_ABORT ON(SQL Server)或在应用层捕获异常后手动调用 rollback()。
常见做法是用结构化错误处理包裹事务:
- SQL Server:
BEGIN TRY ... COMMIT; END TRY BEGIN CATCH ROLLBACK; END CATCH - MySQL 存储过程里可声明
DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK; - 应用代码中(Python/Java)必须在
except或catch块里显式调用conn.rollback(),不能只打印日志就完事
已 COMMIT 的数据,ROLLBACK 无效
COMMIT 一执行,修改就落盘且不可逆。此时 ROLLBACK 会提示 “no transaction in progress” 或直接报错。
误操作后唯一补救路径是外部机制:
- MySQL:依赖
binlog_format = ROW+mysqlbinlog --stop-datetime回放 - PostgreSQL:依赖
archive_mode = on+ WAL 归档 +pg_restore或 PITR - 没有备份/日志?只能从应用日志、缓存、前端提交记录里人工对账修复
SAVEPOINT 支持部分回滚,但别滥用
想回滚事务中某几步,而不是全部,可以用 SAVEPOINT:
START TRANSACTION;
INSERT INTO logs VALUES ('step1');
SAVEPOINT sp1;
INSERT INTO logs VALUES ('step2');
-- 发现 step2 有问题
ROLLBACK TO sp1;
COMMIT;
注意:
-
ROLLBACK TO sp1只撤销sp1之后的操作,sp1之前仍保留 - 所有主流数据库都支持,但 SQL Server 的
@@TRANCOUNT在嵌套事务中行为特殊:一次ROLLBACK会清空全部层级 - 过度拆分 SAVEPOINT 会让逻辑难维护,优先考虑“小事务 + 明确边界”,而不是一个大事务里塞十个保存点
事务是否能回滚,不取决于你有没有写 ROLLBACK,而取决于你有没有把它放进一个未提交的事务上下文中——这个上下文必须由你亲手建立,数据库不会替你猜意图。










