【问题标题】:Need a way to intercept only a Duplicate key exception in MSSQL需要一种方法来仅拦截 MSSQL 中的重复键异常
【发布时间】:2012-12-15 15:28:32
【问题描述】:

假设您的 MSSQL 2008 数据库中存在唯一索引约束违规,如下所示:

Violation of PRIMARY KEY constraint 'PK_ManufacturerCode'. Cannot insert duplicate key in object 'dbo.ManufacturerCode'. The duplicate key value is (8410179)

目前我正在通过胖客户端中的全局异常处理程序处理此异常(使用 ADO 在 Delphi 6 中编写,但没关系,我计划将来使用 C#.NET)并且异常消息附加到一个日志框。

但我想亲自处理这个特定的重复键异常,并使用胖客户端自己的文本在客户端中显示适当的错误消息。我可以解析匹配的错误消息,但出于两个原因不会这样做:

  • 这不是正确的做法 - 最好依靠一些错误代码;
  • 胖客户端旨在使用不同语言的各种 MSSQL 服务器版本,可能有不同的错误文本

使用带有自定义退出代码的 RETURN 或不断调用特殊的存储过程来检查重复项并不能让我感到高兴。

【问题讨论】:

    标签: sql-server exception-handling unique-constraint duplicate-data


    【解决方案1】:

    AFAIK,区分重复键异常的唯一方法是解析错误消息。

    更好的解决方案是首先防止重复键异常。写插入不插入重复键,如果添加了行,请检查@@rowcount

    insert  YourTable
            (id, col1, col2)
    select  1, 'a', 'b'
    where   not exists
            (
            select  *
            from    YourTable yt2
            where   yt2.id = 1
            )
    
    if @@rowcount = 0
        -- Duplicate key!
    

    【讨论】:

    • 问题在于 MSSQL 和胖客户端之间的通信(@@rowcount=0 时出现的问题),而不是如何检测重复键。
    • 我解释了您的标题Need a way to intercept only a Duplicate key exception in MSSQL,因为您只关心重复键异常。我认为 Andomar 这样做了,所以您可能需要重新表述这个问题。
    • 请注意,如果有任何对 YourTable 的并发访问,您需要正确管理锁定。 @@rowcount 可能会在其他人将重复值插入表之前返回零;假设它为下一个操作锁定了表的代码可能没有这样做,并且会导致重复行发生错误,而当它碰巧检查时并不存在。
    【解决方案2】:

    幸运的是,您不必解析文本。 SqlException 具有 Number 属性。观察,返回什么号码并匹配它。数字定义明确。您甚至可以在其中一个系统目录表中查看所有这些表(没有方便的名称)。

    您的想法非常好,只捕捉一个非常具体的错误,而不是只捕捉所有SqlExceptions(例如)。

    【讨论】:

    • 您的回答对我来说似乎不错,但是...我可以通过这种方式检测出哪个列违规发生了吗?
    • 不,不幸的是,这需要解析消息。一般来说,我建议您只尝试插入已知良好的数据。插入前检查。将错误处理为对不良数据的响应通常不是最佳策略。较少的控制(如您在此处看到的)和异常非常慢。也有倒退的感觉。
    • 是的,“插入前检查”对我来说似乎也是正确的。谢谢,我真的很感激......
    • “插入前检查”的问题是它需要两次到服务器的往返,并且在它们中间它容易受到竞争条件的影响。只需插入并等待约束解除即可解决这两个问题,但代价是在影响多行时无法轻松判断哪个是重复项。
    • @Alejandro 是的,这是一种不同的权衡。我已经看到并做过这两种方式,并且每种方式在我的经验中都有自己的位置。不过,您可以在一个非常简单的操作中使用 MERGE 进行检查,但是对于较小的故障率,这可能仍然有点慢。正如你肯定知道的那样,这场比赛可以通过各种方式解决,但这也有一些(小)缺点。
    【解决方案3】:

    在 ADO 中,您将在发生错误后访问连接 Errors 属性,并检查 NativeError 属性以获取 SQL Server 特定的错误号。

    当您切换到 .NET 时,与 SqlExceptionSqlErrorNumber 属性公开相同的数字

    但是,查找特定的错误编号可能有点麻烦 - 对于重复键,错误编号为 2627。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-13
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多