插入阅读大量的文章和与上述有关的主题很多答案之后,我仍然不知道SQL Server数据库引擎在下面的例子中是如何工作的:SQL Server中锁 - 避免重复条目
让我们假设我们有一个表名为T3:
create table t3 (a int , b int);
create index test on t3 (a);
和查询如下:
INSERT INTO T3
SELECT -86,-86
WHERE NOT EXISTS (SELECT 1 FROM t3 where t3.a=-86);
查询验证该行母鹿后插入表中的T3线路根据列“a”不存在。
许多文章和答案表明,使用上面的查询是没有办法,一个行将被插入两次。
对于上述查询的执行,我假设数据库引擎的工作原理如下:
- 子查询首先执行。
- 数据库引擎设置范围上的共享锁定。
- 读取数据。
- 共享锁被释放。根据MSDN,只要数据 被读取,共享的 锁就会被释放。
- 如果一行不存在,它会在表中插入一条新行。
- 新线路被锁定的独占锁(X)
现在考虑以下情形:
- 上面的查询是由处理器A(SPID 1)执行。
- 相同的查询由 处理器B(SPID 2)执行。
- [SPID 1]数据库引擎设置共享锁
- [SPID 1]子查询读取 数据。现在行被返回。
- [SPID 1]发布了共享锁 。
- [SPID 2]数据库引擎设置(一个或多个)共享一个 锁定
- [SPID 2]子查询读取 数据。没有行返回。
- [SPID 2]已发布共享锁 。
- 这两个过程进行行插入(并且我们得到一个重复的条目)。
我这么想吗?上述方式是避免重复输入的正确方法吗?
一种安全的方式,以避免重复条目是使用下面的代码,但我只是想知道上述方法是否正确。
begin tran
if (SELECT 1 FROM t3 with (updlock) where t3.a=-86)
begin
INSERT INTO T3
SELECT -86,-86
end
commit
这是正确的。这两个陈述必须包含在交易中。我纠正了这个问题中的陈述。 所以你说如果我们不强制更新锁,那么INSERT INTO ... WHERE NOT EXISTS(...)语法将不起作用。这就是我所知道的,但是在阅读了很多文章之后,甚至没有提到这些,我开始怀疑它是否真的需要。谢谢澄清。 – yioann 2009-12-06 00:47:49