【问题标题】:@@ERROR and/or TRY - CATCH@@ERROR 和/或 TRY - CATCH
【发布时间】:2009-07-10 19:25:59
【问题描述】:

Try-Catch 会捕获@@ERROR 可以捕获的所有错误吗?在下面的代码片段中,检查@@ERROR 是否值得? RETURN 1111 会发生吗?

SET XACT_ABORT ON
BEGIN TRANSACTION

BEGIN TRY
    --do sql command here  <<<<<<<<<<<

    SELECT @Error=@@ERROR
    IF @Error!=0
    BEGIN
        IF XACT_STATE()!=0
        BEGIN
            ROLLBACK TRANSACTION
        END
        RETURN 1111
    END

END TRY
BEGIN CATCH

    IF XACT_STATE()!=0
    BEGIN
        ROLLBACK TRANSACTION
    END
    RETURN 2222

END CATCH

IF XACT_STATE()=1
BEGIN
    COMMIT
END

RETURN 0

【问题讨论】:

    标签: sql-server sql-server-2005 tsql


    【解决方案1】:

    以下文章是 SQL Server MVP Erland Sommarskog 的必读文章:Implementing Error Handling with Stored Procedures

    还要注意Your TRY block may fail, and your CATCH block may be bypassed

    还有一点:使用旧式错误处理和保存点的存储过程在与 TRY ... CATCH 块一起使用时可能无法按预期工作。Avoid mixing old and new styles of error handling.

    【讨论】:

    • Erland Sommarskog 的链接文章适用于 SQL Server 2000。有关他关于 SQL Server 2005 的文章,请参见此处:sommarskog.se/error_handling_2005.html
    • @RichardMarskell-Drackir 有没有适用于 SQL Server 2008 的?我的意思是链接说 2005 年及以后,但是..
    • @Apostrofix - 与 2000 年至 2005 年之间的变化相比,2005 年以后的变化应该相对较小,所以我想 2005 年的文章仍然适用。
    • Erland Sommarskog 的链接文章已再次移动并重新定位和修改here
    【解决方案2】:

    TRY/CATCH 陷阱更多。它非常好,令人惊讶。

    DECLARE @foo int
    
    SET @foo = 'bob' --batch aborting pre-SQL 2005
    SELECT @@ERROR
    GO
    SELECT @@ERROR  --detects 245. But not much use, really if the batch was a stored proc
    GO
    
    
    DECLARE @foo int
    BEGIN TRY
        SET @foo = 'bob'
        SELECT @@ERROR
    END TRY
    BEGIN CATCH
        SELECT ERROR_MESSAGE(), ERROR_NUMBER()
    END CATCH
    GO
    

    在触发器中使用 TRY/CATCH 也可以。触发器回滚过去也可以批量中止:如果在触发器中也使用了 TRY/CATCH,则不再是。

    如果 BEGIN/ROLLBACK/COMMIT 在构造内部而不是外部,您的示例会更好

    【讨论】:

      【解决方案3】:

      尝试 Catch 不会捕获所有内容

      这里有一些代码来证明这一点

          BEGIN TRY
            BEGIN TRANSACTION TranA
           DECLARE  @cond INT;
           SET @cond =  'A';
          END TRY
          BEGIN CATCH
           PRINT 'a'
          END CATCH;
          COMMIT TRAN TranA
      

      服务器:消息 3930,级别 16,状态 1,第 9 行 当前事务无法提交,也无法支持写入日志文件的操作。回滚事务。 服务器:消息 3998,级别 16,状态 1,行 1 在批处理结束时检测到不可提交的事务。事务被回滚。

      【讨论】:

      • 为什么在 try 中没有开始/提交?
      • 同样的结果,你需要检查 XACT_STATE 来确定,因为仍然是不可捕获的错误和注定的状态
      • 是的,但是里面的提交会转移到 catch 块并且永远不会运行。而且您也希望在 catch 块中回滚。此外,OP 具有自动回滚的 SET XACT_ABORT ON。
      • 我明白我只是想说明 catch 并不能捕获所有内容。我总是在我的 procs 中使用 SET XACT_ABORT ON
      • 我也使用它,但是当提交在 try/catch 之外时,我看不到你是如何演示的
      【解决方案4】:

      我认为控制永远不会到达 RETURN 语句——一旦你在一个 TRY 块中,任何引发的错误都会将控制转移到 CATCH 块。但是,有一些非常严重的错误可能会导致批处理甚至连接本身中止(Erland Sommarskog 写过关于 SQL Server 中的错误的主题herehere——不幸的是,他还没有更新它们包括 TRY...CATCH)。我不确定你是否能捕捉到这种错误,但是@@ERROR 也不好。

      【讨论】:

      • 不,您无法捕获严重性高于 20 的错误。此外,您无法捕获警告。
      【解决方案5】:

      根据我的经验,根据联机丛书,TRY...CATCH 块将捕获所有会产生错误的事件(因此,将 @@ERROR 设置为非零值)。我想不出任何不适用的情况。所以不,返回值永远不会设置为 1111,并且不值得包含 @@Error 检查。

      但是,错误处理可能非常关键,我会在诸如 DTC、链接服务器、通知或代理服务以及其他我很少使用的 SQL 功能等边缘情况下下注。如果可以,请测试您更奇怪的情况,看看实际会发生什么。

      【讨论】:

        【解决方案6】:

        “Try..Catch”的全部意义在于您不必为每个语句检查@@ERROR。

        所以不值得。

        【讨论】:

        • 您的意思是在TRY...CATCH 中检查@@ERROR 是不值得的。你原来的陈述不清楚。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-14
        • 2014-11-27
        • 1970-01-01
        • 2011-02-20
        • 1970-01-01
        • 2011-10-26
        相关资源
        最近更新 更多