1

我在 IIS7 上使用经典的 ASP 和 SQL Server 2005。我有一个流程,一个接一个地向客户发布序列化的产品项目。当我们真的很忙时,我会看到两个用户拉同一行的情况,例如 ID5,相隔一两秒。

似乎用户 2 选择了用户 1 之前一两秒选择的同一行,然后用户 2 也被分配了记录 ID5,在我的更新可以将其专门分配给用户 1 之前,因此,强制用户 2 采取下一个记录。

我可能有 10 件商品MyTable,4 件已售出,6 件有货。所以下一条可用的记录是 ID5

基本上,我的选择代码是两部分:

第1部分:

Select top 1 * 
from MyTable 
where ProdNumber = 'ProdNum' and Sold = 0  order by id

那么,如果存在:

第2部分:

update MyTable 
set Sold = 1 
where id = 'record selected above'

用户 1 将抓取记录 ID5,然后在 PART2 执行之前,用户 2 抓取相同的记录 ID5。结果是用户 1 的第 2 部分被用户 2 直接覆盖为记录 ID5 上的买方。

我已经阅读并阅读了这个论坛和其他关于锁定的内容,但没有看到任何似乎直接适用于我的情况和代码方法的内容。有没有人对我有什么建议。除了退出 SQL Server 和 Classic ASP 之外?提前致谢。

4

2 回答 2

0

SQL Server 通常的工作方式是在正在读取的行上设置共享锁,并在正在更新的行上请求排他锁。共享锁与另一个共享锁兼容——因此两个用户可以同时读取同一行。

您可以做的是向 SQL Server 发出信号,表明您不仅仅是在选择显示 - 而且您确实打算更新您稍后正在阅读的那一行。在这种情况下,在读取该行时会在该行上放置一个更新锁,并且该更新锁与同一行上的第二个更新锁不兼容 - 因此基本上防止第二个用户在用户 1 已经读取该行时读取该行。

因此,您基本上需要将“读取然后更新”步骤放入事务中,并在您的SELECT

BEGIN TRANSACTION

SELECT TOP 1 * 
FROM MyTable WITH (UPDLOCK)
WHERE ProdNumber = 'ProdNum' AND Sold = 0  
ORDER BY id

UPDATE MyTable 
SET Sold = 1 
WHERE id = 'record selected above'

COMMIT TRANSACTION

请参阅有关表提示的相关 MSDN 文档,并阅读有关UPDLOCK更多背景信息的部分。

于 2013-04-08T06:05:41.490 回答
0

您没有使用交易,因此您应该在更新之前检查已售状态并通知用户或提出异常是在读取之前记录已被修改。

IF EXISTS(SELECT * FROM MyTable WHERE id='record selected above' AND Sold=0)
update MyTable set Sold = 1 where id = 'record selected above'
ELSE 
RAISERROR(...)
于 2013-04-08T02:37:19.337 回答