假设UserA和UserB都打开了一个应用程序,并且正在使用相同类型的数据。 UserA将记录插入表中,值为10(PrimaryKey ='A'),UserB当前未看到UserA输入的值,并尝试插入新值20(PrimaryKey ='A')。在这种情况下我想要的是DBConcurrencyException,但我所拥有的是主键违规。我理解为什么,但我不知道如何解决这个问题。处理这种情况的好习惯是什么?我不想在更新数据库之前进行合并,因为我想要一个错误通知用户多个用户更新了这些数据。
答案 0 :(得分:5)
在这种情况下我想要的是DBConcurrencyException,但我所拥有的是主键违规。我理解为什么
这是这种情况的正确例外。您说您想通知用户该值已经插入,因此只需捕获主键异常,然后再回吐用户友好的消息。
答案 1 :(得分:2)
这是你必须做出的设计决定 - 你想使用悲观或乐观的锁定吗?
我太懒了 - quoted from this thread:
这些是用于处理多用户问题的方法。如何处理2个人想要同时更新同一记录的事实?
什么都不做
用户2现在已经覆盖了用户1所做的更改。它们完全消失了,好像它们从未发生过一样。这称为“丢失更新”。
读取时锁定记录。 悲观锁定
丢失的更新问题已解决。这种方法的问题是并发性。用户1正在锁定他们可能永远不会更新的记录。用户2甚至无法读取记录,因为他们在阅读时也想要独占锁定。这种方法需要太多的独占锁定,而且锁的使用寿命太长(通常跨越用户控制 - 绝对禁止 - 否)。这种方法几乎从未实施。
使用乐观锁定。 乐观锁定在阅读时不使用排他锁。相反,在更新期间进行检查以确保记录在读取后未被更改。这可以通过检查表中的每个字段来完成。 即。 UPDATE Table1 SET Col2 = x WHERE COL1 =:OldCol1 AND COl2 =:OldCol AND Col3 =:OldCol3 AND ... 当然,这有几个缺点。首先,您必须已经从表中选择了每一列。其次,你必须构建并执行这个庞大的声明。 大多数人通过单个列(通常称为时间戳)实现此目的。除了实现乐观并发之外,此列仅用于而不是用于其他目的。它可以是数字或日期。想法是在插入行时给出一个值。每当读取记录时,也会读取timestamp列。执行更新时,将检查时间戳列。如果它在UPDATE时具有与读取时相同的值,则一切正常,执行UPDATE并且时间戳已更改!。如果时间戳值在UPDATE时间不同,则会向用户返回错误 - 他们必须重新读取记录,重新进行更改,并尝试再次更新记录。
答案 2 :(得分:2)
如果在并发用户插入 NEW 记录时遇到PK违规,则会发生以下两种情况之一:
违规发生在自然密钥上,具有业务价值的密钥,如用户名或类似密钥。 PK违规是由于业务流程缺陷而发生的,即。两个不同的运营商尝试插入相同的业务项目。如何应对的逻辑完全由业务领域特定规则驱动,我们不可能给出任何建议。
违规发生在代理键上,即。像CustomerID或类似的标识符。在这种情况下,缺陷完全依赖于应用程序代码,因为它意味着它使用有缺陷的算法来生成新的ID。同样,如果不了解如何生成新ID,则无法提供有效的建议。
答案 3 :(得分:0)
一个解决方案可能涉及桌面上的INSTEAD OF INSERT
触发器。
在这里,您将覆盖触发器中的INSERT语句。当您检测到主键'A'已存在行或值时,您将有机会RAISEERROR。