我的select-insert程序中是否需要锁定提示?

时间:2016-07-21 17:07:23

标签: sql-server

如果行键尚不存在,我有一个存储过程会在表中插入一行。它看起来像这样:

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。

我的问题是:这有足够的预防措施来预防问题吗?我是否需要在select语句中添加任何提示?如果是,我需要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 个答案:

答案 0 :(得分:1)

您希望将事务隔离级别标记为serializable。否则,有人可以在您的交易中途插入具有相同ID的行。这被称为"幻象行"。

您不需要锁定整个桌子。通过使用正确的隔离级别,SQL Server可以更智能地了解它如何应用其锁定。