Я много читал о предотвращении состояний гонки, но обычно с одной записью в сценарии upsert. Например: Атомарный UPSERT в SQL Server 2005
У меня другое требование, и оно состоит в том, чтобы предотвратить состояние гонки между несколькими строками. Например, скажем, у меня есть следующая структура таблицы:
GiftCards:
GiftCardId int primary key not null,
OriginalAmount money not null
GiftCardTransactions:
TransactionId int primary key not null,
GiftCardId int (foreign key to GiftCards.GiftCardId),
Amount money not null
Может быть несколько процессов, вставляемых в GiftCardTransactions
, и мне нужно предотвратить вставку, если SUM(GiftCardTransactions.Amount) + insertingAmount
превысит GiftCards.OriginalAmount
.
Я знаю, что могу использовать TABLOCKX
на GiftCardTransactions
, но, очевидно, это невозможно для большого количества транзакций. Другой способ - добавить столбец GiftCards.RemainingAmount
, а затем мне нужно заблокировать только одну строку (хотя и с возможностью эскалации блокировки), но, к сожалению, в настоящее время это не вариант для меня (было бы это лучшим вариантом?) .
Вместо того, чтобы пытаться предотвратить вставку в первую очередь, возможно, ответ состоит в том, чтобы просто вставить, затем выбрать SUM(GiftCardTransactions.Amount)
и, если необходимо, выполнить откат. Это крайний случай, поэтому меня не беспокоит излишнее использование значений PK и т. Д.
Итак, вопрос в том, как я могу добиться этого с минимальным количеством блокировок, не изменяя структуру таблицы и не используя любую комбинацию транзакций, уровней изоляции и подсказок?