SET XACT_ABORT ON是确保事务错误时自动回滚的关键设置;默认OFF导致错误后事务状态异常,后续DML报“上下文事务已被终止”,须在存储过程首行显式启用并配合TRY...CATCH与ROLLBACK使用。

这是 SQL Server 明确告诉你:当前会话的事务已因错误被强制回滚,后续语句无法再参与该事务。 根本原因几乎总是 SET XACT_ABORT OFF(默认值)+ 错误未被捕获 + 事务未显式结束,导致事务状态进入“不可用但未清理”的中间态。
SET XACT_ABORT OFF 是默认陷阱
SQL Server 存储过程创建时默认不开启 XACT_ABORT。这意味着哪怕 THROW 或 RAISERROR 抛出严重错误,执行流仍可能继续——但事务内部状态已被标记为“终止”,后续任何 DML 都会触发“上下文事务已被终止”提示。
- 必须在
CREATE PROC或ALTER PROC的第一行就写:SET XACT_ABORT ON; - 不能只在调用前
SET,也不能放在逻辑中间;否则无效 - 验证是否生效:
SELECT XACT_ABORT FROM sys.dm_exec_sessions WHERE session_id = @@SPID;返回1才算真正启用
TRY...CATCH 没包住关键 DML 就等于没设防
很多人以为加了 TRY...CATCH 就万事大吉,但若 DML 语句写在 TRY 块外,或 CATCH 里漏掉 ROLLBACK TRANSACTION,事务照样残留异常状态。
-
THROW在CATCH外直接使用会失败;无参THROW只能在CATCH内重抛 -
RAISERROR不自动回滚,必须紧跟着ROLLBACK TRANSACTION; RETURN; - 推荐结构:整个业务逻辑包进
TRY,CATCH中统一ROLLBACK+THROW(SQL Server 2012+)
客户端没处理好连接复用也会传染错误状态
连接池中某个连接曾因未捕获错误而遗留了 @@TRANCOUNT > 0 状态,下次复用该连接时,新执行的存储过程一碰事务就报错。
- 应用层应在每次调用后检查
@@TRANCOUNT,非零则主动ROLLBACK - 连接字符串中可加
Connection Reset=true(SQL Server),或调用sp_reset_connection清理 - 避免在存储过程中依赖外部事务——它不可控,也不可预测
真正麻烦的不是错误本身,而是事务状态和连接状态的耦合:一个没关严的 TRY、一行漏写的 ROLLBACK、一次没 reset 的连接,都可能让下一条语句在毫无征兆的情况下撞上“上下文事务已被终止”。

















