并发的SQL表锁定[重复]

Posted

技术标签:

【中文标题】并发的SQL表锁定[重复]【英文标题】:SQL Table locking for concurrency [duplicate] 【发布时间】:2013-09-20 20:11:31 【问题描述】:

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

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

我有一个名为 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 的解决方案。

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

【问题讨论】:

“如何防止这种情况发生?”:我要做的第一件事就是添加唯一索引。 【参考方案1】:

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

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

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

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

延伸阅读:SQL Server ROWLOCK over a SELECT if not exists INSERT transactionhttp://technet.microsoft.com/en-us/library/ms187373.aspx

【讨论】:

很好的建议,但我也试过了。问题是我需要锁定整个表,而不仅仅是单行。 (我需要锁定整个表,因为可能没有要锁定的行。) @user2800568 你需要holdlock 来锁定每个副本的范围,updlock 而不是xlock 以避免死锁。看看骗子。【参考方案2】:

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

【讨论】:

以上是关于并发的SQL表锁定[重复]的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 事务/并发混乱 - 你必须总是使用表提示吗?

锁定机制和数据并发管理(笔记)

锁定 SQL Server 表以进行写入但不用于读取 [重复]

论 大并发 下的 乐观锁定 Redis锁定 和 新时代事务

SQL Server 表隔离级别和锁定问题

与表锁定相关的 Spark Hive 插入