2016-06-13 81 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; 
相關問題