这是关于如何在表中不存在时锁定值范围(以及其他任何内容!)的一般问题。这个问题的触发器是我想要“插入如果不存在”,我不想使用MERGE
,因为我需要支持SQL Server 2005。
在第一个连接中我:
begin transaction
(SERIALIZABLE, ROWLOCK)
+ where子句从表中选择数据以重新指定范围在第二个连接中,我将数据插入到表中,其值不匹配第一个连接中的where子句
我希望第二个连接不受第一个连接的影响,但只有在我提交(或回滚)第一个连接的事务后才会完成。
我错过了什么?
这是我的测试代码:
首先创建此表:
CREATE TABLE test
(
VALUE nvarchar(100)
)
其次,打开新的查询窗口sql server managements studio并执行以下命令:
BEGIN TRANSACTION;
SELECT *
FROM test WITH (SERIALIZABLE,ROWLOCK)
WHERE value = N'a';
第三步,打开另一个新的查询窗口并执行以下命令:
INSERT INTO test VALUES (N'b');
请注意,在第一个窗口中的事务结束之前,第二个查询不会结束
答案 0 :(得分:8)
您缺少VALUE
上的索引。
如果没有SQL Server没有任何内容可以使用key range lock并且将锁定整个表以锁定范围。
即使添加了索引,您仍会遇到问题中的方案阻塞。 RangeS-S
锁定不会锁定查询中指定的特定范围。相反,它会锁定所选范围任一侧的键之间的范围。
当任何一侧没有这样的键时,范围锁会延伸到无穷大。您需要在a
和b
之间添加一个值(例如aa
),以防止在您的测试中发生这种情况并阻止插入b
。
有关此内容的详情,请参阅本文中的Bonus Appendix: Range Locks。