我处于一个位置,我将获得一个 GUID 列表,这些 GUID 将由 SQL Server 数据库在运行时分配。
我的直接想法是为 GUID 创建一个表。当订购一批 GUID 时,它们将被插入到表中。
然后,在运行时,将调用一个 SPROC 从表中选择一个 GUID。我可以检索下一个 GUID 并立即从表中删除它,或者检索下一个 GUID 并更新另一列以将其声明为已使用。
但这让我想知道同时对数据库进行两次调用以获得 GUID 的竞争条件的可能性。在我看来,如果时间完全不方便,则可以为这两个调用检索相同的 GUID。
Q1:我担心这种潜在的竞争状况是否正确?即它会发生吗?
Q2:有没有办法避免这种情况(例如设置一个 SPROC 来阻止每次调用?)
我能想到的一种至少可以使竞争条件失败的方法是设置另一个进行 GUID 分配的表,并将 GUID 列设置为唯一。然后,在运行时过程中,当检索到 GUID 时,它将通过 GUID 分配表分配给产品。如果为两种产品颁发了相同的 GUID,那么当需要分配它们时,其中一种产品将无法分配并被拒绝。
基本上,您正在寻找对队列表中下一行的独占访问权。假设这种表:
此过程将序列化删除而不阻止另一个会话获取下一个值:
或者,如果您想更新:
您可以像这样从队列中取出下一个项目:
然后
@guid
用于您需要做的任何后续处理。要测试它是否已序列化,请将其放在两个窗口中:
运行一个,然后另一个,两者都会得到一个值。不要忘记同时提交。
Remus 和 gbn 讨论了为什么要将这三个锁定锁定提示用于出队查询。
如果您想观察在没有这些提示的情况下会发生什么(也许这是您想要的行为),请将它们注释掉,更改过程,然后重复上面的实验 - 您会看到第一个阻止第二个,直到第一次提交。无论你认为你能在多近的时间上取得胜利,一个会赢,另一个会等待。但是不要通过在任何一种情况下将过程调用包装在事务中来加剧这种情况。您想要这样做的唯一原因是您想“撤消”出队操作。如果由于某些情况或异常而最终没有使用队列外的 GUID,那么,好吧,认为这是一种损失(或者您总是可以将该值插入回队列中)。
如上所述,不要忘记提交第二个事务。
我在这里写过类似的东西(生成一大堆你不必确认的唯一数字的美妙之处是以后是唯一的),但在那篇文章中我没有说明如果你想回滚索赔该怎么做:
您可能会考虑添加某种后台进程来监控队列的大小(或剩余多少无人认领的行,在这种情况下过滤索引可能会很方便),以便您可以在新行到达时自动补充某个点(而不是用完中间交易)。确保您的后台进程以一种智能的方式计算行数。