0

我试图确保只有一行插入到表中,但我遇到了多个进程相互碰撞并且我得到不止一行的问题。这是详细信息(可能比需要的更多详细信息,抱歉):

有一个名为“区域”的表,其中包含“区域”的层次结构。每个“区域”都可能在订单表中有待处理的“订单”。由于它是一个层次结构,因此可以将多个“区域”分组在一个父“区域”下。

我有一个名为 FindNextOrder 的存储过程,给定一个区域,找到下一个挂单(可能在子区域中)并“激活”它。“激活”意味着将 OrderID 插入到 QueueActive 表中。业务规则是一个区域一次只能有一个活动订单。

所以我的存储过程有这样的语句:

IF EXISTS (SELECT 1 FROM QueueActive WHERE <Order exists for the given area>) RETURN
...
INSERT INTO QueueActive <Order data for the given area>

我的问题是每隔一段时间,两个不同的进程会几乎同时调用这个存储过程。当每个人检查现有行时,每个人都返回零。因此,两个进程都执行插入语句,我最终得到两个活动订单,而不仅仅是一个。

我该如何防止这种情况?哦,我碰巧使用的是 SQL Server 2012 Express,但我需要一个同样适用于 SQL Server 2000、2005 和 2008 的解决方案。

我已经搜索了专门锁定表并找到了这个答案,但我尝试实现它失败了。

4

2 回答 2

0

如果表中有一个活动订单,您是否尝试过创建一个回滚第二个事务的触发器?

于 2013-09-20T20:58:11.327 回答
0

我会在您的 select 语句中使用一些查询提示。问题来了,因为您的程序只取出共享锁,因此其他程序可以加入。

将 WITH (ROWLOCK, XLOCK, READPAST) 标记到您的 SELECT

ROWLOCK 确保您只锁定行。
XLOCK 在该行上取出一个排他锁,这样其他人就无法读取它。
READPAST 允许查询跳过任何锁定的行并继续工作而不是等待。

最后一个是可选的,取决于您的并发要求。

进一步阅读:
SQL Server ROWLOCK over a SELECT if not exists INSERT transaction
http://technet.microsoft.com/en-us/library/ms187373.aspx

于 2013-09-20T20:27:56.583 回答