违反主键约束,多个用户

时间:2010-06-11 21:41:36

标签: .net sql-server concurrency primary-key

假设UserA和UserB都打开了一个应用程序,并且正在使用相同类型的数据。 UserA将记录插入表中,值为10(PrimaryKey ='A'),UserB当前未看到UserA输入的值,并尝试插入新值20(PrimaryKey ='A')。在这种情况下我想要的是DBConcurrencyException,但我所拥有的是主键违规。我理解为什么,但我不知道如何解决这个问题。处理这种情况的好习惯是什么?我不想在更新数据库之前进行合并,因为我想要一个错误通知用户多个用户更新了这些数据。

4 个答案:

答案 0 :(得分:5)

  

在这种情况下我想要的是DBConcurrencyException,但我所拥有的是主键违规。我理解为什么

这是这种情况的正确例外。您说您想通知用户该值已经插入,因此只需捕获主键异常,然后再回吐用户友好的消息。

答案 1 :(得分:2)

这是你必须做出的设计决定 - 你想使用悲观或乐观的锁定吗?

我太懒了 - quoted from this thread

这些是用于处理多用户问题的方法。如何处理2个人想要同时更新同一记录的事实?

  1. 什么都不做

    • 用户1读取记录
    • 用户2读取相同的记录
    • 用户1更新该记录
    • 用户2更新同一记录

    用户2现在已经覆盖了用户1所做的更改。它们完全消失了,好像它们从未发生过一样。这称为“丢失更新”。

  2. 读取时锁定记录。 悲观锁定

    • 用户1通过在记录上添加独占锁(FOR UPDATE子句)来读取记录并将其锁定
    • 用户2尝试读取并锁定相同的记录,但现在必须在用户1后面等待
    • 用户1更新记录(当然,提交)
    • 用户2现在可以使用用户1所做的更改
    • 来读取记录
    • 用户2使用来自用户1的更改
    • 更新记录

    丢失的更新问题已解决。这种方法的问题是并发性。用户1正在锁定他们可能永远不会更新的记录。用户2甚至无法读取记录,因为他们在阅读时也想要独占锁定。这种方法需要太多的独占锁定,而且锁的使用寿命太长(通常跨越用户控制 - 绝对禁止 - 否)。这种方法几乎从未实施。

  3. 使用乐观锁定。 乐观锁定在阅读时不使用排他锁。相反,在更新期间进行检查以确保记录在读取后未被更改。这可以通过检查表中的每个字段来完成。 即。 UPDATE Table1 SET Col2 = x WHERE COL1 =:OldCol1 AND COl2 =:OldCol AND Col3 =:OldCol3 AND ... 当然,这有几个缺点。首先,您必须已经从表中选择了每一列。其次,你必须构建并执行这个庞大的声明。 大多数人通过单个列(通常称为时间戳)实现此目的。除了实现乐观并发之外,此列仅用于而不是用于其他目的。它可以是数字或日期。想法是在插入行时给出一个值。每当读取记录时,也会读取timestamp列。执行更新时,将检查时间戳列。如果它在UPDATE时具有与读取时相同的值,则一切正常,执行UPDATE并且时间戳已更改!。如果时间戳值在UPDATE时间不同,则会向用户返回错误 - 他们必须重新读取记录,重新进行更改,并尝试再次更新记录。

    • 用户1读取记录,包括时间戳21
    • 用户2读取记录,包括时间戳21
    • 用户1尝试更新记录。 had(21)中的时间戳与数据库中的时间戳(21)匹配,因此执行更新并更新时间戳(22)。
    • 用户2尝试更新记录。手中的时间戳(21)匹配数据库(22)中的时间戳,因此返回错误。用户2现在必须重新读取记录,包括新的时间戳(22)和用户1的更改,重新应用他们的更改并重新尝试更新。

答案 2 :(得分:2)

如果在并发用户插入 NEW 记录时遇到PK违规,则会发生以下两种情况之一:

  • 违规发生在自然密钥上,具有业务价值的密钥,如用户名或类似密钥。 PK违规是由于业务流程缺陷而发生的,即。两个不同的运营商尝试插入相同的业务项目。如何应对的逻辑完全由业务领域特定规则驱动,我们不可能给出任何建议。

  • 违规发生在代理键上,即。像CustomerID或类似的标识符。在这种情况下,缺陷完全依赖于应用程序代码,因为它意味着它使用有缺陷的算法来生成新的ID。同样,如果不了解如何生成新ID,则无法提供有效的建议。

答案 3 :(得分:0)

一个解决方案可能涉及桌面上的INSTEAD OF INSERT触发器。

在这里,您将覆盖触发器中的INSERT语句。当您检测到主键'A'已存在行或值时,您将有机会RAISEERROR