AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 2296
Accepted
kacalapy
kacalapy
Asked: 2011-04-21 11:19:55 +0800 CST2011-04-21 11:19:55 +0800 CST 2011-04-21 11:19:55 +0800 CST

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

  • 772

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

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

sql-server-2005 stored-procedures
  • 3 3 个回答
  • 3463 Views

3 个回答

  • Voted
  1. Best Answer
    Phil Helmer
    2011-04-21T23:19:44+08:002011-04-21T23:19:44+08:00

    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,它在构建错误消息时增加了一些灵活性,特别是用于记录目的。

    • 12
  2. gbn
    2011-04-22T05:14:12+08:002011-04-22T05:14:12+08:00

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

    笔记:

    • 如果没有 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
    
    • 7
  3. datagod
    2011-04-24T19:49:44+08:002011-04-24T19:49:44+08:00

    我使用 Try/Catch,但我也会收集尽可能多的信息,并在回滚后将其写入错误日志。在此示例中,“LogEvent”是一个写入 EventLog 表的存储过程,其中包含所发生事件的详细信息。GetErrorInfo() 是一个返回确切错误消息的函数调用。

    当发生错误时,收集信息,过程跳到错误处理部分并发出回滚。信息被写入日志,然后程序退出。

    考虑到涉及的额外过程/函数调用,它似乎有点过头了。但是,此方法在尝试调试问题时非常有用。

    exec LogEvent @Process, @Database, '试图插入等等等等'
    开始尝试
      插入 MyTable
      选择值
        来自 MyOtherTable
    
      选择@rowcount = @@ROWCOUNT
    结束尝试
    -- 错误处理
    开始捕捉
      选择@error = ERROR_NUMBER(),
             @rowcount = -1,
             @TableAction = '插入',
             @TableName = @Database + '.MyTable',
             @AdditionalInfo = '(尝试插入等等等等)' + dbo.GetErrorInfo()
       GOTO 表访问错误
    结束捕获
    
    .
    .
    .
    .
    
    表访问错误:
    IF (@@TRANCOUNT > 0) 回滚
    选择@output = 上(@TableAction)+
           ' ERROR - 发生错误时 ' +
           案例(@TableAction)
             当'更新'然后'更新'
             当'删除'然后'删除'
             否则@TableAction + 'ing'
           结束 +
           '记录' +
           案例(@TableAction)
             当'选择'然后'来自'
             当“更新”然后“进入”
             当'插入'然后'进入'
             否则“来自”   
             结束 +
             ' ' + @TableName + ' 表。'
    选择 @output = @output + ' @@ERROR: ' + convert(varchar(8),@error)
    选择@output = @output + '@@ROWCOUNT:' + 转换(varchar(8),@rowcount)
    
    选择 @output = @output + isnull(@AdditionalInfo,'')
    执行 LogEvent @Process、@Database、@Output
    RAISERROR(@output,16,1) 带日志
    选择@ReturnCode = -1
    转到 THE_EXIT
    
    
    
    • 3

相关问题

  • 有人在实践中使用过 sqlcmd 模式吗?[关闭]

  • 是否有人使用 SQL Server 功能来创建按编号区分的存储过程组?

  • 如何在不安装新实例的情况下更改 MS SQL 2005 中的实例名称?

  • MySQL 存储例程中的动态 SQL

  • 从 SQL Server 2008 降级到 2005

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    您如何显示在 Oracle 数据库上执行的 SQL?

    • 2 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    我可以查看在 SQL Server 数据库上运行的历史查询吗?

    • 6 个回答
  • Marko Smith

    如何在 PostgreSQL 中使用 currval() 来获取最后插入的 id?

    • 10 个回答
  • Marko Smith

    如何在 Mac OS X 上运行 psql?

    • 11 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Marko Smith

    将数组参数传递给存储过程

    • 12 个回答
  • Martin Hope
    Manuel Leduc PostgreSQL 多列唯一约束和 NULL 值 2011-12-28 01:10:21 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Stuart Blackler 什么时候应该将主键声明为非聚集的? 2011-11-11 13:31:59 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    BrunoLM Guid vs INT - 哪个更好作为主键? 2011-01-05 23:46:34 +0800 CST
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +0800 CST
  • Martin Hope
    Patrick 如何优化大型数据库的 mysqldump? 2011-01-04 13:13:48 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve