2016-07-21 21 views
1

我有一個存儲過程,如果行鍵不存在,則將行插入表中。它看起來像這樣:我的選擇插入程序中是否需要鎖定提示?

create proc EmployeeInsertIfNotExists 
    (@id int, @name varchar(50)) 
as 
begin 
    SET XACT_ABORT ON 

    begin transaction 

    if not exists(select * from tbl where id = @id) 
     insert into tbl(id, name) 
     values(id, name) 

    commit transaction 
end 

這個存儲過程實際上只是兩個語句,一個select和一個可能的插入。我在一個事務中使用了兩個語句,以便在它們之間不會發生任何異常。 id列是主鍵,所以我想確保我不插入兩次相同的ID。

我的問題是:這是否足以防範問題的預防措施?我是否需要在選擇語句中加入任何提示?如果是這樣,我需要HOLDLOCK, TABLOCKX?這是我的新材料。

編輯:建議答案

create proc EmployeeInsertIfNotExists 
    (@id int, @name varchar(50)) 
as 
begin 
    SET XACT_ABORT ON 
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 

    begin transaction 

    if not exists(select * from tbl where id = @id) 
     insert into tbl(id, name) 
     values(id, name) 

    commit transaction 
end 

回答

1

要標記事務隔離級別serializable。否則,某人可以在您的交易中途插入具有相同ID的行。這被稱爲「幻影行」。

您不需要鎖定整個表格。通過使用正確的隔離級別,SQL Server可以更智能地應用其鎖。

+0

那麼我需要將我的程序更改爲我粘貼的第二個程序嗎?我可以通過使用merge'語句完全避免事務嗎? – user2023861

+0

是的,你的第二個版本應該可以工作。不,合併不是原子的。它具有與原始版本相同的問題。 –

+1

這是對你正在嘗試做的事情的矯枉過正。可序列化會傷害(殺死?)你機器的性能。如果id對它有一個唯一的約束,那麼將保證沒有其他人可以在該列中插入多於一個的鍵值。您可以從proc返回一個指示插入失敗的值,並且可以使用另一個鍵值再次嘗試。 –

相關問題