SQL:Try/Catch在尝试访问无法找到的表时没有捕获到错误

Luk*_*uke 8 sql database transactions sql-server-2005 try-catch

我创建了一个存储过程来运行许多命令来修改数据.如果一切顺利,我只想提交事务.我是通过以下方式使用try-catch块来实现这一点的(其中我真实的CATCH块使用RAISERROR来返回错误消息):

BEGIN TRY
  BEGIN TRANSACTION
  UPDATE Table1 SET MyVarcharColumn = 'test'
  UPDATE Table2 SET MyBitColumn = 1
  UPDATE Table3 SET MyIntColumn = 42
  COMMIT TRANSACTION
END TRY
CATCH
  ROLLBACK TRANSACTION
END CATCH
Run Code Online (Sandbox Code Playgroud)

这是我想要的方式.例如,如果我将MyBitColumn设置为'b'而不是1,则会捕获错误,控制流到CATCH,并且不会提交事务.

我注意到的一个问题是,如果数据库中不存在Table3,那么它会出错(无效的对象名称),但CATCH块永远不会被执行,并且事务保持打开状态.

我想处理这个问题来处理数据库被修改的任何(远程)可能性(或者在正确添加此存储过程的情况下发生的事情,但其中一个表没有).

我该如何处理这些错误案例?

-谢谢你的帮助.

Mit*_*eat 11

在脚本开始时使用SET XACT_ABORT

SET XACT_ABORT ON
Run Code Online (Sandbox Code Playgroud)

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

我不认为这是可能的:

当CATCH块出现在与TRY ... CATCH构造相同的执行级别时,它们不会处理以下类型的错误:

  • 编译阻止批处理运行的错误,例如语法错误.

  • 语句级重新编译期间发生的错误,例如由于延迟名称解析而在编译后发生的对象名称解析错误.

参考.

下面的示例显示了如何由SELECT语句生成的对象名称解析错误未被TRY ... CATCH构造捕获,但在存储过程内执行相同的SELECT语句时,CATCH块会捕获该错误.

USE AdventureWorks2012;
GO

BEGIN TRY
    -- Table does not exist; object name resolution
    -- error not caught.
    SELECT * FROM NonexistentTable;
END TRY
BEGIN CATCH
    SELECT 
        ERROR_NUMBER() AS ErrorNumber
        ,ERROR_MESSAGE() AS ErrorMessage;
END CATCH
Run Code Online (Sandbox Code Playgroud)

错误未被捕获,控制从TRY ... CATCH构造传递到下一个更高级别.