9

我创建了一个存储过程,它运行许多命令来修改数据。如果一切顺利,我只想提交交易。我通过以下方式使用 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

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

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

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

我应该如何处理这些错误情况?

-谢谢你的帮助。

4

2 回答 2

12

在脚本开始时使用SET XACT_ABORT

SET XACT_ABORT ON

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

我认为这是不可能的:

以下类型的错误发生在与 TRY...CATCH 构造相同的执行级别时,不会由 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

错误没有被捕获,并且控制从 TRY…CATCH 构造传递到下一个更高级别。

于 2013-02-22T00:55:20.133 回答
0
EXECUTE ('SELECT * FROM NonexistentTable');
于 2017-05-18T19:15:45.297 回答