首页 > 解决方案 > 如果不存在则插入以避免竞争条件

问题描述

如何确保以下语句没有竞争条件?

IF NOT EXISTS (select col1 from Table1 where SomeId=@SomeId)
INSERT INTO Table1 values (@SomeId,...)

IF NOT EXISTS (select col1 from Table2 where SomeId=@SomeId)
INSERT INTO Table2 values (@SomeId,...)

这够了吗

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRAN

IF NOT EXISTS (SELECT col1 FROM Table1 WITH (UPDLOCK) WHERE SomeId=@SomeId)
INSERT INTO Table1 VALUES (@SomeId,...)

COMMIT TRAN

BEGIN TRAN

IF NOT EXISTS (SELECT col1 FROM Table2 WITH (UPDLOCK) WHERE SomeId=@SomeId)
INSERT INTO Table2 VALUES (@SomeId,...)

COMMIT TRAN

标签: sql-servertsql

解决方案


是的。足够了。将事务隔离级别设置为可序列化将创建SomeId=@SomeId在您运行 select 时覆盖的键锁——这将防止其他进程SomeId=@SomeId在您的事务运行时插入具有相同键 ( ) 的值。

WITH(UPDLOCK)提示将导致 SELECT 获取所选行(如果存在)的更新锁。这将防止其他事务在您的事务运行时修改这些行(如果它们在选择时存在)。

看起来您并不需要WITH(UPDLOCK)提示,因为如果记录已经存在,您将立即提交事务。如果您想在记录确实存在的情况下在提交之前做其他事情,您可能需要这个提示 - 但实际上,您似乎不需要。


推荐阅读