Събрах следния скрипт, за да докажа този трик, който използвах преди години. Ако го използвате, ще трябва да го промените, за да отговаря на вашите цели. Следват коментари:
/*
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. По-горе стойността на "флаг" се задава само ако актуализацията работи (т.е. критериите за актуализация са изпълнени); в противен случай няма да се промени (тук, оставен на нула), можете да проверите за това и да обработите съответно.
Що се отнася до транзакцията и превръщането й в сериализираема, бих искал да знам повече за това какво трябва да бъде капсулирано в транзакцията, преди да предложа как да продължа.
-- Допълнение, продължение на втория коментар по-долу ------------
Идеите на г-н Saffron са задълбочен и солиден начин за внедряване на тази рутина, тъй като вашите първични ключове се дефинират отвън и се предават в базата данни (т.е. не използвате колони за самоличност - добре от мен, те често се използват прекалено много).
Направих още няколко теста (добавих ограничение за първичен ключ към колона ContentId, обвих UPDATE и INSERT в транзакция, добавих подсказката за сериализиране към актуализацията) и да, това трябва да направи всичко, което искате. Неуспешната актуализация задейства заключване на диапазон на тази част от индекса и това ще блокира всички едновременни опити за вмъкване на тази нова стойност в колоната. Разбира се, ако N заявки са изпратени едновременно, "първият" ще създаде реда и той ще бъде незабавно актуализиран от втория, третия и т.н. - освен ако не зададете "заключването" някъде по реда. Добър трик!
(Имайте предвид, че без индекса в ключовата колона бихте заключили цялата таблица. Освен това заключването на диапазона може да заключи редовете от „двете страни“ на новата стойност – или може би няма да го направят, аз не тествайте това. Не би трябвало да има значение, тъй като продължителността на операцията трябва [?] да бъде в едноцифрени милисекунди.)