SQL Server表锁定和解锁问题

4

我有一个非常有趣的问题。

我有一个数据表,内容如下: DVDSerialNumbers(ID, Create_Date, SerialNumber, CategoryID)

我的应用程序生成DVD的序列号,我有一个像这样的SQL命令(由我的应用程序发出):

ExecuteQuery("select top {0} SerialNumber from DVDSerialNumbers where CategoryID = {1};" & 
"delete from DVDSerialNumbers where ID in (select top{0} ID from DVDSerialNumber where " & 
 "CategoryID = {1});", n, CategoryID)

ExecuteQuery会返回我的select查询结果,但同时也会执行删除命令。

基本上,我只得到给定CategoryID的n个序列号,并删除它们的行。

然而,这里存在并发问题。如果以上代码在同一时间运行两次,则结果可能相同,但是想要从表中获取给定的SerialNumber仅一次。

如何才能让B实例等待A实例完成此命令?我应该锁定表吗?还是应该锁定某些行?或者有更好的解决方案?

提前感谢您的帮助。


你的数据库隔离级别设置是什么?在尝试优化查询之前,您需要了解这一点。 - Neil Fenwick
1
@Neil Fenwick:不需要:这不是隔离级别问题。 - gbn
1个回答

3
您需要使用READPAST、UPDLOCK和ROWLOCK提示。有关更多信息,请参见:SQL Server进程队列竞争条件 然后您需要为SELECT/DELETE使用一个事务。相反,您可以使用一个语句和一个OUTPUT子句来完成这个操作。
ExecuteQuery("delete top ({0})
                  DVDSerialNumbers WITH (READPAST, UPDLOCK, ROWLOCK)
              OUTPUT DELETED.SerialNumber
              where CategoryID = {1}" & 
                , n, CategoryID)

谢谢您的回答,我会考虑一下并尽快给您回复。再次感谢。 - Lajos Arpad
实际上这是一个很好的答案,我认为这就是解决方案。不过关于CategoryID有一个语法错误,但是这个想法非常好。再次感谢你。 - Lajos Arpad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接