小编yio*_*ann的帖子

SQL Server锁定 - 避免插入重复的条目

在阅读了很多文章和许多与上述主题相关的答案后,我仍然想知道SQL Server数据库引擎如何在以下示例中工作:

我们假设我们有一个名为t3的表:

create table t3 (a int , b int);
create index test on t3 (a);
Run Code Online (Sandbox Code Playgroud)

和查询如下:

INSERT INTO T3
SELECT -86,-86
WHERE NOT EXISTS (SELECT 1 FROM t3 where t3.a=-86);
Run Code Online (Sandbox Code Playgroud)

在根据列"a"验证该行尚不存在之后,查询在表t3中插入一行.

许多文章和答案表明使用上述查询无法将行插入两次.

为了执行上面的查询,我假设数据库引擎的工作原理如下:

  1. 子查询首先执行.
  2. 数据库引擎在范围上设置共享锁.
  3. 读取数据.
  4. 共享锁已释放.根据MSDN,一旦读取数据就会释放共享锁.
  5. 如果某行不存在,则在表中插入一个新行.
  6. 新行被锁定(x)

现在考虑以下场景:

  1. 上述查询由处理器A(SPID 1)执行.
  2. 处理器B(SPID 2)执行相同的查询.
  3. [SPID 1]数据库引擎设置共享锁
  4. [SPID 1]子查询读取数据.现在返回行.
  5. [SPID 1]共享锁被释放.
  6. [SPID 2]数据库引擎设置共享锁
  7. [SPID 2]子查询读取数据.没有行返回.
  8. [SPID 2]共享锁被释放.
  9. 两个进程都继续插入行(我们得到一个重复的条目).

我错过了什么吗?上述方法是避免重复输入的正确方法吗?

避免重复输入的安全方法是使用下面的代码,但我只是想知道上述方法是否正确.

begin tran
    if (SELECT 1 FROM t3 with (updlock) where t3.a=-86)
    begin
        INSERT INTO T3
        SELECT -86,-86
    end
commit
Run Code Online (Sandbox Code Playgroud)

sql sql-server

2
推荐指数
1
解决办法
4620
查看次数

标签 统计

sql ×1

sql-server ×1