在VBA应用程序中捕获SQL错误时遇到一些问题之后,我重新设计了存储过程,以便在发生错误时,返回值是错误代码,输出变量包含错误消息。我不在catch块中重新抛出错误。由于没有更好的术语,我将称之为“优雅退出”。它使客户端的工作变得更容易,但现在当嵌套存储过程触发的触发器回滚事务时,我遇到了一个问题。
以下面的示例为例。TEST_INNER_PROC
以@@TRANCOUNT
为1开始,执行引发触发器的插入操作,该操作回滚事务,当TEST_INNER_PROC
退出时,它抛出错误
266:EXECUTE之后的事务计数指示开始和COMMIT语句的数目不匹配
通常,我会将这两个过程模式化为相同的;我在这里对它们进行了简化。内部过程不会尝试启动事务(这不会有什么不同),外部过程会重新抛出错误,这样我就可以看到打印的错误信息。通常,我会通过返回代码和@ERR_MSG
输出变量将错误代码返回给客户端。
我喜欢@gbn的模式:嵌套存储过程包含TRY CATCH ROLLBACK模式?但是,如果回滚发生在触发器中,它似乎不适合我的“优雅退出”。我也不确定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
以上代码将产生:
消息266,级别16,状态2,程序TEST_INNER_PROC,第63行
EXECUTE之后的事务计数指示开始和COMMIT语句的数目不匹配。上一个计数= 1,当前计数= 0。
但是如果您取消注解TEST_INNER_PROC中的“THROW”语句,它将抛出:
消息50001,级别16,状态1,程序TEST_TRIGGER,第69行
TEST触发程序产生错误。
这是我想在TEST_OUTER_PROC
中处理的错误。
有没有可能使用“优雅地退出”的存储过程,将错误代码和错误消息作为变量返回,并避免BEGIN
和COMMIT
语句的不匹配数量?
1条答案
按热度按时间evrscar21#
您可以将所有错误存储在表中并从中选择它们
在您的程序中:
程序执行后:
更新:创建一个视图,这样您也可以获得文本: