SQL Server Perform a get-row-if-exists-otherwise-create query

oo7oh9g9  于 2023-08-02  发布在  其他
关注(0)|答案(2)|浏览(90)

I'm working within a microservice environment and have two independent Azure serverless functions that both perform a SQL INSERT if a prior SELECT returns no row. Each serverless function runs on an as-needed basis based on various triggers. At times, the functions can be running at the exact same time which appears to be exposing a race condition. The race condition being that both functions will first check if a row exists in a table and if it does not exist it will create it, but if both functions do this at the same time then the both see that no record exists and one creates it while the otherwise fails due to a unique key constraint in the database table.

What approaches are there for me to remove this race condition?

Is there a solution that I can perform purely in SQL (a query, locking, stored procedure, etc) that would allow me to leverage that solution in my code without having to go with a larger code modification to fix the issue?

4zcjmb1e

4zcjmb1e1#

Is there a solution that I can perform purely in SQL

Yes. In a transaction, check for the row with the (UPDLOCK,HOLDLOCK) query hints.

eg

begin transaction

if not exists (
  select *
  from sometable with (updlock,holdlock)
  where Name = @SomeName
)
begin
  insert into sometable(...)   
end

commit transaction

This will lock the target row (or empty range) so if two sessions run this at the same time, one will be blocked on SELECT until the other commits the insert.

b4lqfgs4

b4lqfgs42#

Assuming what you mean is that you want to actually see the result of that row:

You can actually do this in a single statement using MERGE .

DECLARE @found bit;

MERGE sometable WITH (UPDLOCK, HOLDLOCK) AS t
USING (VALUES (@Id, @SomeValue) ) AS v(Id, SomeValue)
  ON t.Id = v.Id
WHEN NOT MATCHED THEN
  INSERT (Id, SomeValue)
  VALUES (v.Id, v.SomeValue)
WHEN MATCHED THEN UPDATE
  SET @found = 1
OUTPUT inserted.*;

But given that MERGE is known to have bugs, I would still advise a separate IF NOT EXISTS ... INSERT and SELECT pairs.

相关问题