Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Insert if not exists avoiding race condition

How can I make sure following statements don't have a race condition?

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,...)

Is this enough

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
like image 518
Jenks Avatar asked Oct 14 '25 05:10

Jenks


1 Answers

Yes. That is enough. Setting the transaction isolation level to serializable will create key locks that cover SomeId=@SomeId when you run your select-- which will prevent other processes from inserting values with the same key (SomeId=@SomeId) while your transaction is running.

The WITH(UPDLOCK) hint will cause the SELECT to obtain an update lock on the selected row(s), if they exist. This will prevent other transactions from modifying these rows (if they existed at the time of the select) while your transaction is running.

It doesn't look like you really need the WITH(UPDLOCK) hint, since you are committing the transaction right away if the record already exists. If you wanted to do something else before committing if the record does exist, you might need this hint-- but as it is, it appears you do not.

like image 129
Tim Avatar answered Oct 16 '25 22:10

Tim



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!