TSQL-在事务中运行过程时出错,其中过程包括事务



在存储过程中,我有一个带有事务的try-catch块,如果控制从未传递到catch,则该块将提交;否则,如果出现错误,并且控制确实传递到了catch块,则会回滚。

我在事务中运行这个存储过程,如下例所示:

CREATE PROCEDURE sp_test
AS
BEGIN
BEGIN TRY
BEGIN TRAN
DECLARE @var INT = 1
IF @var <> 2 
BEGIN
RAISERROR('error', 16,1)
END
COMMIT
END TRY
BEGIN CATCH
ROLLBACK
PRINT 'Rolled back'
END CATCH
END

BEGIN TRAN
EXEC sp_test

当我运行这个时,我看到错误

Msg 266,Level 16,State 2,Procedure sp_test,Line 0[Batch Start Line 7]
EXECUTE之后的事务计数指示BEGIN和COMMIT语句的数量不匹配。上一个计数=1,当前计数=0。

但我不明白为什么。

我正在存储过程之外启动一个事务。然后我将进入SP并开始另一个事务。一旦控制权传递到catch块,两个事务都应该回滚,因此事务计数应该为0。

显然,我的理解有差距。

这种行为是经过设计的。每当事务启动时,@@TRANCOUNT会话变量都会增加一个,当事务提交时,它会减少一个。但是,当事务回滚时,它会回滚所有嵌套的事务。因此,在您的情况下,catch中的回滚将回滚2个嵌套事务,@@TRANCOUNT将变为0。这将导致调用者抛出不匹配事务计数异常。

为了避免这个问题,您可以在SP中检查@@TRANCOUNT,只在它为0时启动一个新事务,并设置一个标志(本地变量(来指示,例如@new_tarn=1。然后,只有在@new_tran=1时才提交或回滚。

最新更新