从存储过程中优雅地退出并避免BEGIN / COMMIT不匹配

时间:2016-07-30 05:35:02

标签: sql-server vba stored-procedures transactions try-catch

在我的VBA应用程序中捕获SQL错误时遇到了一些问题,我重新设计了我的存储过程,以便在发生错误时,返回值是错误代码,输出变量包含错误消息。我不会在我的catch块中重新抛出错误。由于缺乏一个更好的术语,我会称之为“优雅退出”。它使客户端的操作变得更容易,但是当嵌套存储过程触发的触发器回滚事务时,我遇到了一个问题。

采用以下示例。 TEST_INNER_PROC@@TRANCOUNT为1开头,执行插入触发触发器,回滚事务,当TEST_INNER_PROC退出时抛出错误

  

266:EXECUTE之后的事务计数表示BEGIN和COMMIT语句的数量不匹配

通常情况下,我会将这两个程序的模式相同;我在这里简化了它们。内部过程不会尝试启动事务(它不会产生任何影响),并且外部过程会重新抛出错误,这样我就可以看到打印的错误信息。通常,我会通过返回码和@ERR_MSG输出变量将错误代码返回给客户端。

我喜欢@ gbn的模式:Nested stored procedures containing TRY CATCH ROLLBACK pattern?但是,如果在触发器中发生回滚,它似乎不适合我的“优雅退出”。我也不确定Rusanu's pattern 也适应它。

CREATE TABLE TEST (
    COL1 INT
)
GO

CREATE TRIGGER TEST_TRIGGER
ON TEST FOR INSERT
AS
BEGIN TRY
    THROW 50001, 'TEST Trigger produced an error.', 1
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0 AND XACT_STATE()<>0
    ROLLBACK TRAN;
    THROW
END CATCH
GO

CREATE PROC TEST_INNER_PROC
AS
SET NOCOUNT, XACT_ABORT ON
DECLARE @RTN INT = 0
BEGIN TRY
    INSERT TEST (COL1) VALUES (1)
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0 AND XACT_STATE()<>0
    ROLLBACK TRAN
    SET @RTN = ERROR_NUMBER();
    --THROW
END CATCH
RETURN @RTN
GO

CREATE PROC TEST_OUTER_PROC
AS
SET NOCOUNT, XACT_ABORT ON
DECLARE @RTN INT = 0
BEGIN TRY
    BEGIN TRAN
        EXEC @RTN = TEST_INNER_PROC
        IF @RTN <> 0 THROW 50000, 'Execution of TEST_INNER_PROC produced an error.', 1
    COMMIT TRAN
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0 AND XACT_STATE()<>0
    ROLLBACK TRAN;
    THROW
END CATCH
GO

EXEC TEST_OUTER_PROC
GO

DROP TABLE TEST
DROP PROC TEST_OUTER_PROC
DROP PROC TEST_INNER_PROC
GO

上面的代码导致:

  

Msg 266,Level 16,State 2,Procedure TEST_INNER_PROC,Line 63
  EXECUTE之后的事务计数表示BEGIN的数量不匹配   和COMMIT语句。先前的计数= 1,当前计数= 0。

但如果您取消注释TEST_INNER_PROC中的“THROW”语句,它会抛出:

  

Msg 50001,Level 16,State 1,Procedure TEST_TRIGGER,第69行   TEST触发器产生错误。

这是我要在TEST_OUTER_PROC中处理的错误。

是否可以使用“正常退出”的存储过程,将错误代码和错误消息作为变量返回,并避免BEGINCOMMIT语句的不匹配数量?

0 个答案:

没有答案