存储过程出错时为什么会提交部分事务?

you*_*gme 8 sql-server stored-procedures transaction

我有一个存储过程,它首先声明一些变量,然后包含begin tran;在此之后它对提供的参数执行一些验证(并且每次提供的参数验证失败时都会增加错误计数)。如果没有错误计数,则继续执行 7 次插入。在此之后,它有commit tran;

最近我在列表中添加了第 8 个插入。隐式类型转换意味着某些插入的数据在插入时会被截断。这向 SSMS 屏幕抛出了一个错误,但我发现前 7 个插入已提交,而第 8 个显然没有完成。

我很欣赏我可以包含一个try ... catch块来处理错误,但如果一个显式begin tran;不能使整个工作块自主到commit,那么有什么意义呢?我错过了什么?

我知道我也许可以将我的程序调用包装在那个级别的事务中 - 但是有人可以解释发生了什么以及为什么begin tran当包含在程序主体中时似乎不受尊重吗?如果调用该过程开始一个隐式事务,那么 proc 中的错误步骤不应该回滚受 proc 影响的所有更改 - 即使没有明确包含begin tran在 proc 主体中?

AMt*_*two 15

事务不会在出错时自动回滚——这不是它们的设计目的。它们旨在让您能够回滚。但是,您仍然需要做一些事情来实现这一点。

正如您所提到的,您可以通过 实现这一点TRY...CATCH,这使您可以最大程度地控制是否以及如何回滚。

听起来您期望 的行为SET XACT_ABORT ON,您可以在存储过程中设置它,但不是默认行为。文档中关于设置XACT_ABORTon vs off的描述是:

当 SET XACT_ABORT 为 ON 时,如果 Transact-SQL 语句引发运行时错误,则整个事务将终止并回滚。

当 SET XACT_ABORT 为 OFF 时,在某些情况下,只会回滚引发错误的 Transact-SQL 语句,并且事务继续处理。根据错误的严重程度,即使 SET XACT_ABORT 为 OFF,整个事务也可能会回滚。OFF 是 T-SQL 语句中的默认设置,而 ON 是触发器中的默认设置。


SET XACT_ABORT是时ON,调用故障过程会在 SSMS 中返回消息,例如:

Msg 8152, Level 16, State 14, Procedure spProcName, Line 298 [Batch Start Line 5]
String or binary data would be truncated.

Completion time: 2021-04-26T10:51:00.8420902+10:00
Run Code Online (Sandbox Code Playgroud)

第一行在 SSMS 中为红色。

SET XACT_ABORTis 时OFF,调用故障过程包括一条附加消息:

Msg 8152, Level 16, State 14, Procedure spProcName, Line 298 [Batch Start Line 5]
String or binary data would be truncated.
The statement has been terminated.

Completion time: 2021-04-26T10:53:52.5951780+10:00
Run Code Online (Sandbox Code Playgroud)

特别是,当您看到以下消息时,这意味着已提交过程中错误语句之前的语句:

The statement has been terminated.
Run Code Online (Sandbox Code Playgroud)