避免在SQL Server中插入重复记录

时间:2015-09-25 05:29:14

标签: sql-server database

我一直无法找到答案。假设我有以下表/查询:

表格:

create table ##table
(
   column1 int,
   column2 nvarchar(max)
)

查询(在现实生活中,条件会更复杂):

declare @shouldInsert bit
set @shouldInsert = case when exists(
    select * 
    from ##table
    where column2 = 'test') then 1 else 0 end

--Exaggerating a possible delay:
waitfor delay '00:00:10'

if(@shouldInsert = 0)
   insert into ##table
   values(1, 'test')

如果我同时运行此查询两次,那么它可能会插入重复的记录(由于现实条件比整个表中的“column1”唯一性更为复杂,因此难以接受唯一约束)

我看到两种可能的解决方案:

  1. 我在可序列化模式下运行两个并发事务,但它会创建一个死锁(首先是select中的共享锁,然后是insert中的x-lock - 死锁)。

  2. 在select语句中,我使用查询提示(update,tablock),这将有效地x锁定整个表,但它会阻止其他事务读取数据(我想避免的事情)< / p>

  3. 哪个更容易接受?有第三种解决方案吗?

    感谢。

2 个答案:

答案 0 :(得分:1)

如果可以的话,你应该在任何定义唯一性的列上加上 UNIQUE 约束(或索引)。

有了这个,你可能仍然得到&#34;好的,还不存在&#34;对两个独立进程的初始检查的响应 - 但是其中一个将首先插入他的行,而第二个将获得一个&#34;违反的唯一约束&#34;从数据库返回异常。

答案 1 :(得分:0)

无论你如何“参与”你的“现实生活条件”,你有两个选择:强制执行UNIQUE或处理多个记录。任何解决方案都可能很脆弱。

例如,如果您需要添加另一个数据库服务器或压倒性负载会降低单个线程的执行速度,那么delay hack就没用了

允许多个应该是唯一值的副本的方法之一是创建另一个可以充当队列但不强制唯一性的表,以及一个串行工作程序来使其出列。或者更改数据结构以允许1对多,并在查询时选择第一个。仍然是一个黑客,但至少不是非常“创造性”,它不能打破