Вставьте, если не существует, избегая состояния гонки - PullRequest
0 голосов
/ 04 июня 2018

Как я могу убедиться, что следующие утверждения не имеют условия гонки?

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

Ответы [ 2 ]

0 голосов
/ 05 июня 2018

Выписка является транзакцией

declare @v int = 11;
insert into iden (val) 
select @v
where not exists (select 1 from iden with (UPDLOCK) where val = @v) 
0 голосов
/ 05 июня 2018

Да.Этого достаточно.Установка уровня изоляции транзакции в serializable создаст блокировки ключа, которые охватывают SomeId=@SomeId при запуске select, что не позволит другим процессам вставлять значения с тем же ключом (SomeId=@SomeId) во время выполнения транзакции.

Подсказка WITH(UPDLOCK) заставит SELECT получить блокировку обновления для выбранных строк, если они существуют.Это не позволит другим транзакциям изменять эти строки (если они существовали на момент выбора) во время выполнения вашей транзакции.

Не похоже, что вам действительно нужен WITH(UPDLOCK) подсказка, так как высовершить транзакцию сразу, если запись уже существует.Если вы хотели сделать что-то еще перед фиксацией, если запись существует, вам может понадобиться эта подсказка - но на самом деле, похоже, вы этого не делаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...