【问题标题】:SQL: Try/Catch doesn't catch an error when attempting to access a table that it can't findSQL:尝试访问无法找到的表时,Try/Catch 未捕获错误
【发布时间】:2013-02-22 00:51:22
【问题描述】:

我创建了一个存储过程,它运行许多命令来修改数据。如果一切顺利,我只想提交交易。我通过以下方式使用 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 块永远不会执行并且事务保持打开状态。

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

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

-感谢您的帮助。

【问题讨论】:

    标签: sql database sql-server-2005 transactions try-catch


    【解决方案1】:

    在脚本的开头使用SET XACT_ABORT

    SET XACT_ABORT ON
    

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

    我认为这是不可能的:

    以下类型的错误不会由 CATCH 块处理 它们与 TRY...CATCH 结构发生在同一执行级别:

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

    • 语句级重新编译时出现的错误,如编译后出现的对象名解析错误,因为 延迟名称解析。

    Ref.

    以下示例显示对象名称解析错误是如何发生的 由 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 传递出去 建设到下一个更高的水平。

    【讨论】:

    • 谢谢。导致事务回滚的设置很有用。但是,它仍然不执行错误发生后 CATCH 块中的内容。这适用于我的应用程序(因为无论如何都会向上传递错误)但是如果有人试图确保 CATCH 块由于其他原因执行,则不会这样做。
    • 啊,明白了,在这种情况下,他们只是没有因为这些类型的错误而被捕获。谢谢!
    【解决方案2】:
    EXECUTE ('SELECT * FROM NonexistentTable');
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-21
      • 2014-03-04
      • 1970-01-01
      • 1970-01-01
      • 2019-01-12
      • 2023-01-14
      • 2015-03-30
      相关资源
      最近更新 更多