MySQL存储过程UPDATE失败不回滚,因未声明错误处理器;必须用DECLARE CONTINUE/EXIT HANDLER FOR SQLEXCEPTION显式ROLLBACK,否则事务不自动中断或回滚。

MySQL存储过程里UPDATE失败后不回滚,是因为没声明错误处理器
MySQL默认不会因单条SQL报错就中断后续语句,更不会自动回滚——哪怕你写了START TRANSACTION。必须显式用DECLARE CONTINUE HANDLER FOR SQLEXCEPTION捕获错误并触发ROLLBACK,否则INSERT INTO t1失败后,UPDATE t2照常执行。
- 用
CONTINUE时,handler执行完继续往下走;用EXIT则直接退出当前BEGIN...END块 - 别依赖
@@error或@@rowcount判断:它们只反映上一条语句结果,无法捕获约束冲突等异常 -
DECLARE EXIT HANDLER比CONTINUE更常用,避免残留逻辑干扰事务状态
SQL Server中多条UPDATE混杂跨库调用,回滚必须靠TRY/CATCH+显式TRAN
在SQL Server里,仅靠IF @@ERROR 0逐条检查不可靠:它不捕获运行时错误(如死锁、超时),且跨库调用(如dblink)的错误可能不写入@@ERROR。必须用BEGIN TRY...BEGIN CATCH包裹整个事务块,并在CATCH里调用ROLLBACK。
-
RAISERROR要带状态码(如16)才能被CATCH捕获,PRINT不行 - 跨库操作前确认目标库连接可用,否则
CATCH可能收不到错误信号 - 避免在
TRY块里嵌套其他事务——SQL Server不支持嵌套事务,@@TRANCOUNT只会增减1
级联更新失败时,触发器补偿不能替代事务回滚
用AFTER UPDATE触发器同步关联表(如orders.user_name随users.name更新)是常见做法,但它和主事务不在同一个原子单元里:主表更新成功但触发器里UPDATE orders失败,主事务已提交,无法靠ROLLBACK拉回。
- 触发器内不要做复杂查询或调用存储过程,MySQL 5.7+对触发器内事务控制脆弱
- 若需强一致性,把级联逻辑提到应用层,用单事务包住所有表的
UPDATE - 真要用触发器,必须在触发器末尾加
IF ROW_COUNT() = 0日志兜底,而不是指望它“自动修复”
已提交的UPDATE无法ROLLBACK,只能靠备份+日志还原
一旦执行了COMMIT或连接断开导致事务隐式提交,ROLLBACK就彻底失效。这时候再找事务回滚是徒劳的,得切到外部恢复路径。
- MySQL需确认
log_bin=ON且二进制日志保留足够久,用mysqlbinlog定位误操作位置 - SQL Server依赖完整备份+事务日志备份链,
RESTORE DATABASE ... WITH STOPAT可精确还原到出错前一秒 - 日常必须养成习惯:线上DML前先
SELECT验证条件,高并发环境加LIMIT 10试跑,别信“只改一行”的直觉

















