Я собрал следующий скрипт, чтобы подтвердить этот трюк, который использовал в прошлые годы. Если вы используете его, вам нужно изменить его в соответствии с вашими целями. Комментарии следуют:
/*
CREATE TABLE Item
(
Title varchar(255) not null
,Teaser varchar(255) not null
,ContentId varchar(30) not null
,RowLocked bit not null
)
UPDATE item
set RowLocked = 1
where ContentId = 'Test01'
*/
DECLARE
@Check varchar(30)
,@pContentID varchar(30)
,@pTitle varchar(255)
,@pTeaser varchar(255)
set @pContentID = 'Test01'
set @pTitle = 'TestingTitle'
set @pTeaser = 'TestingTeasier'
set @check = null
UPDATE dbo.Item
set
@Check = ContentId
,Title = @pTitle
,Teaser = @pTeaser
where ContentID = @pContentID
and RowLocked = 0
print isnull(@check, '<check is null>')
IF @Check is null
INSERT dbo.Item (ContentID, Title, Teaser, RowLocked)
values (@pContentID, @pTitle, @pTeaser, 0)
select * from Item
Хитрость в том, что вы можете устанавливать значения в локальных переменных в операторе Update. Выше значение «flag» устанавливается только в том случае, если обновление работает (то есть критерии обновления выполнены); в противном случае, оно не будет изменено (здесь, в нуле), вы можете проверить это и обработать соответствующим образом.
Что касается транзакции и ее сериализации, я хотел бы узнать больше о том, что должно быть заключено в транзакцию, прежде чем предлагать, как продолжить.
- Дополнения, продолжение второго комментария ниже -----------
г. Идеи Saffron - это тщательный и надежный способ реализации этой процедуры, поскольку ваши первичные ключи определяются снаружи и передаются в базу данных (т. Е. Вы не используете столбцы идентификаторов - прекрасно, часто они чрезмерно используются).
Я провел еще несколько тестов (добавил ограничение первичного ключа для столбца ContentId, обернул UPDATE и INSERT в транзакцию, добавил в обновление сериализуемую подсказку) и да, это должно делать все, что вы хотите. Неудачное обновление перекрывает блокировку диапазона в этой части индекса, что блокирует любые одновременные попытки вставить это новое значение в столбец. Конечно, если N запросов подано одновременно, «first» создаст строку, и она будет немедленно обновлена вторым, третьим и т. Д., Если вы не установите «lock» где-нибудь вдоль линии. Хороший трюк!
(Обратите внимание, что без индекса для ключевого столбца вы заблокируете всю таблицу. Кроме того, блокировка диапазона может заблокировать строки по обе стороны от нового значения - или, возможно, они не будут, я не проверял это. Не должно иметь значения, поскольку продолжительность операции должна быть [?] в миллисекундах с одной цифрой.)