2016-06-13 57 views
0
CREATE TABLE dbo.SomeTable 
(
    ID int NOT NULL, 
    SomeText varchar(10) NOT NULL 
) ON [PRIMARY] 
GO 

ALTER TABLE dbo.SomeTable 
    ADD CONSTRAINT PK_SomeTable 
    PRIMARY KEY CLUSTERED (ID) 
     WITH(STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
       ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
GO 

CREATE PROCEDURE [dbo].[InsertSomeText] 
    @ID int, 
    @SomeText varchar(10) 
AS 
BEGIN 
    BEGIN TRANSACTION 

    DELETE FROM SomeTable WHERE ID = @ID 

    INSERT INTO SomeTable (ID, SomeText) 
    VALUES (@ID, @SomeText) 

    COMMIT TRANSACTION  
END 

上述的存储过程有时会引发错误PRIMARY KEY约束存储过程抛出PRIMARY KEY约束违反

冲突

当在相同称为时间与价值相同@ID

删除/插入操作在事务中,所以我认为这将是一个原子操作,但仍然有一段时间它会抛出异常。

+2

没关系与过程是在事务内。如果他们都在同一时间开始,他们都只是试图插入相同的ID。 – DavidG

+5

这可能是一个愚蠢的问题,因为我认为这是一个简化版本,但为什么删除,然后插入时,你可以简单地更新? –

+4

...或者MERGE'声明? –

回答

2

实际上有避免竞争条件的极少数傻瓜证明方法,利用交易不,除非你指定锁定级别其中之一。不幸的是,我从来没有见过使用删除和插入来管理upsert,所以我找不到任何文档或测试来显示竞争条件发生的方式和原因。

而不是解决一个有些奇怪的方法(删除/插入),我建议干脆用MERGE WITH (HOLDLOCK),这是线程安全的:

CREATE PROCEDURE [dbo].[InsertSomeText] 
    @ID int, 
    @SomeText varchar(10) 
AS 
BEGIN 
    MERGE dbo.SomeTable WITH (HOLDLOCK) AS t 
    USING (VALUES (@ID, @SomeText)) s (ID, SomeText) 
     ON s.ID = t.ID 
    WHEN MATCHED THEN 
     UPDATE SET SomeText = s.SomeText 
    WHEN NOT MATCHED THEN 
     INSERT (ID, SomeText) VALUES (s.ID, s.SomeText); 
END; 
相关问题