稍后使用INSERT SELECT COUNT(SomeId)到相同的SomeId:适当的锁定策略?

时间:2013-11-24 01:19:13

标签: sql sql-server tsql locking deadlock

我正在使用SQL Server 2012.我有一个可重复的读取事务,我执行此查询:

select count(SomeId)
from dbo.MyTable
where SomeId = @SomeId

SomeId是一个列,其值可能在表中重复(想想外键)。但是,SomeId不是任何索引的成员,也不是外键。

在交易的后期,我将dbo.MyTable中的记录插入@SomeId,从而改变select count(*)将返回的内容,我将再次运行它:

insert into dbo.MyTable (SomeId, ...)
values (@SomeId, ...)

我的应用程序中的多个线程可以同时执行此事务。因此,我在insert声明中遇到了僵局。起初,我认为updlock适用于select语句,但我很快意识到它不起作用,因为我实际上并没有更新select count(SomeId)选择的行

我的问题是:有没有办法避免可能昂贵的表锁?有没有办法锁定涉及SomeId的行,即使它们尚未插入(奇怪,我知道)?我希望强制其他线程在原始事务完成其工作时等待,但我不想不必要地锁定行。

修改

这就是我想要完成的事情:

我只想为特定SomeId插入最多八行。有几个不相关的进程可能同时启动其中一个事务。 select count检测是否已有八行并导致该进程的操作失败。如果计数小于8,则同一事务执行额外的工作,然后在末尾插入记录,从而有效地增加计数,select count再次运行。我在insert声明中遇到了僵局。

1 个答案:

答案 0 :(得分:0)

如果您有多个进程尝试执行相同的操作并且您不希望记录多于某个数字,则需要实际阻止这些进程同时运行。

一种方法是使用独占锁读取计数:

select count(SomeId)
from dbo.MyTable with (xlock)
where SomeId = @SomeId 

这样,在事务完成之前,这些记录将被阻止。

您应该为SomeId列创建一个索引,因为锁定很可能会以这种方式保存在索引级别上。