在 SQL 2005 存储过程中添加错误处理的最佳方法是什么?

kac*_*apy 11 sql-server-2005 best-practices stored-procedures

什么是使存储过程足够健壮以使其可以很好地扩展并包含错误处理的好方法?

此外,在存储过程中处理多个错误场景并拥有一个智能反馈系统来向调用应用程序返回有意义的错误信息的最佳方法是什么?

Phi*_*mer 12

Alex Kuznetsov 在他的《防御性数据库编程》(第 8 章)一书中有一个很棒的章节,其中涵盖了 T-SQL TRY...CATCH、T-SQL 事务和 SET XACT_ABORT 设置,以及使用客户端错误处理。它将帮助您决定哪些选项对您需要完成的工作最有意义。

它可以在这个站点免费获得。我与这家公司没有任何关系,但我确实拥有那本书的硬拷贝版本。

有很多关于这个主题的小细节,亚历克斯很好地解释了。

根据尼克的要求......(但并非所有内容都在本章中)

在扩展方面,您需要非常诚实地确定哪些活动需要在数据库代码中,哪些应该在应用程序中。有没有注意到执行代码的速度往往会回到为每个方法的单一关注点设计?

最简单的沟通方式是自定义错误代码(> 50,000)。它也很快。这确实意味着您必须保持数据库代码和应用程​​序代码同步。使用自定义错误代码,您还可以在错误消息字符串中返回有用的信息。因为您有严格针对这种情况的错误代码,所以您可以在应用程序代码中编写一个针对错误数据格式定制的解析器。

另外,数据库中哪些错误条件需要重试逻辑?如果您想在 X 秒后重试,那么最好在应用程序代码中处理它,以免事务阻塞太多。如果您只是立即重新提交 DML 操作,则在 SP 中重复该操作可能会更有效。但请记住,您可能必须复制代码或添加一层 SP 才能完成重试。

真的,这是目前 SQL Server 中 TRY...CATCH 逻辑的最大痛点。这是可以做到的,但它有点傻。寻找 SQL Server 2012 中对此的一些改进,尤其是重新抛出系统异常(保留原始错误号)。此外,还有FORMATMESSAGE,它在构造错误消息方面增加了一些灵活性,特别是用于日志记录目的。


gbn*_*gbn 7

这是我们的模板(已删除错误日志)

笔记:

  • 如果没有 XACT_ABORT,所有 TXN 开始和提交/回滚必须配对
  • 提交递减@@TRANCOUNT
  • 回滚会将 @@TRANCOUNT 返回为零,因此您会收到错误 266
  • 你不能只回滚当前层(例如在回滚时减少@@TRANCOUNT)
  • XACT_ABORT 抑制错误 266
  • 每个存储过程必须符合相同的模板,因此每个调用都是原子的
  • 由于 XACT_ABORT,回滚检查实际上是多余的。然而,它让我感觉更好,没有它看起来很奇怪,并且允许你不想要它的情况
  • 这允许客户端 TXN(如 LINQ)
  • Remus Rusanu有一个使用保存点的类似 shell。我更喜欢原子数据库调用,不要像他们的文章那样使用部分更新

...所以不要创建比你需要的更多的 TXN

然而,

CREATE PROCEDURE [Name]
AS
SET XACT_ABORT, NOCOUNT ON

DECLARE @starttrancount int

BEGIN TRY
    SELECT @starttrancount = @@TRANCOUNT

    IF @starttrancount = 0
        BEGIN TRANSACTION

       [...Perform work, call nested procedures...]

    IF @starttrancount = 0 
        COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION
    RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
GO
Run Code Online (Sandbox Code Playgroud)