如果行键尚不存在,我有一个存储过程会在表中插入一行。它看起来像这样:
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
答案 0 :(得分:1)
您希望将事务隔离级别标记为serializable
。否则,有人可以在您的交易中途插入具有相同ID的行。这被称为"幻象行"。
您不需要锁定整个桌子。通过使用正确的隔离级别,SQL Server可以更智能地了解它如何应用其锁定。