MSSQL Deadlock при обновлении с помощью (updlock)
Я попал в тупик при обновлении. Уровень транзакции установлен на Read Committed
, Как избежать тупика в такой ситуации?
В других случаях WITH (NOLOCK)
а также WITH (UPDLOCK)
помог.
Я получил следующее T-SQL
запрос:
IF EXISTS (SELECT 1 FROM DEBTORS_CUSTOMERS WITH (NOLOCK) WHERE DebtorId = @DebtorId AND ClientFCCustomerNumber = @CustomerNumber)
UPDATE DEBTORS_CUSTOMERS WITH (UPDLOCK) SET StatusId = @StatusId WHERE DebtorId = @DebtorId AND ClientFCCustomerNumber = @CustomerNumber
ELSE
INSERT INTO DEBTORS_CUSTOMERS (DebtorId, ClientFCCustomerNumber, StatusId, DocId) SELECT @DebtorId, @CustomerNumber, @StatusId, @DocId
И вот тупик, который я получил:
<resource-list>
<keylock hobtid="72057594105692160" dbid="63" objectname="EOTestDataGenerator.dbo.DEBTORS_CUSTOMERS" indexname="PK_DEBTORS_CUSTOMERS" id="lockdf8abb00" mode="X" associatedObjectId="72057594105692160">
<owner-list>
<owner id="process3f59048" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="processbdbfa088" mode="U" requestType="wait"/>
</waiter-list>
</keylock>
<keylock hobtid="72057594105692160" dbid="63" objectname="EOTestDataGenerator.dbo.DEBTORS_CUSTOMERS" indexname="PK_DEBTORS_CUSTOMERS" id="lockdf5ab200" mode="X" associatedObjectId="72057594105692160">
<owner-list>
<owner id="processbdbfa088" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="process3f59048" mode="U" requestType="wait"/>
</waiter-list>
</keylock>
</resource-list>
1 ответ
Решение
Вы обрабатываете несколько строк за транзакцию, верно? Это не должно тупик для одного ряда
Вы можете получить двойные вставки, что является ошибкой. Два сеанса могут сделать вывод, что строки нет, и тогда оба будут вставлены.
Есть два способа сделать это безопасно:
- Выдать выбор
WITH (ROWLOCK, UPDLOCK, HOLDLOCK)
которая является известной последовательностью подсказок блокировки. Требуется блокировка, которая стабилизировала данные, с которыми вы работаете. После выполнения этого заявления у вас есть данные для себя. Затем вы можете вставить или обновить. Вы также можете свернуть все три утверждения в одноMERGE
но вам все еще нужны подсказки блокировки. Кроме того, у вас должен быть какой-то глобальный порядок, в котором вы выпускаете записи. Прямо сейчас, независимо от того, как вы блокируете, всегда может быть тупик, если один сеанс записывает A, B, а другой записывает в порядке B, A. Простой способ получить глобальный порядок - выполнить все записи в одномMERGE
заявление. Обработчик запросов обычно выбирает план, который обеспечивает порядок. - использование
SERIALIZABLE
изоляция с повторной попыткой в тупике.