Хобрук: Ваш путь к мастерству в программировании

Сериализуемый тупик транзакции

В документации сказано, что serializable транзакции выполняются одна за другой.

Но на практике это не похоже на правду. Вот две почти равные транзакции, разница всего в 15 секундах.

#1:

set transaction isolation level serializable
go
begin transaction
if not exists (select * from articles where title like 'qwe')
begin
waitfor delay '00:00:15'
insert into articles (title) values ('qwe')
end
commit transaction go

#2:

set transaction isolation level serializable
go
begin transaction
if not exists (select * from articles where title like 'qwe')
begin
insert into articles (title) values ('asd')
end
commit transaction go

Вторая транзакция была запущена через пару секунд после запуска первой.

Результат - тупик. Первая транзакция умирает с

Transaction (Process ID 58) was deadlocked on 
lock resources with another process and has been chosen as the deadlock victim. 
Rerun the transaction.

причина.

Вывод, сериализуемые транзакции не являются серийными?


  • Где сказано, что serializable означает одну транзакцию за раз? Насколько мне известно, уровень изоляции сериализуемых транзакций будет получать эксклюзивные/диапазонные блокировки ресурсов, даже если он только читает данные (на менее строгих уровнях изоляции он получает общую блокировку только при чтении данных) и запрещает другим пользователям даже читать данные. 08.12.2014

Ответы:


1

сериализуемые транзакции не обязательно выполняются последовательно.

Обещание заключается в том, что транзакции могут совершаться только в том случае, если результат будет таким, как если бы они выполнялись последовательно (в любом порядке).

Требования к блокировке для выполнения этой гарантии часто могут приводить к тупиковой ситуации, когда необходимо откатить одну из транзакций. Вам нужно будет закодировать собственную логику повторной попытки, чтобы повторно отправить неудавшийся запрос.

Дополнительную информацию о различия между логическим описанием и реализацией.

08.12.2014
  • Это может происходить тысячи раз при высокой нагрузке, особенно если есть много копий запроса, все из которых запрашивают сериализованный доступ. Это делает режим практически бесполезным, потому что он постоянно блокируется. Вероятно, лучше просто вынуть эксклюзивный столовый замок впереди и удерживать его. Затем запросы, по крайней мере, все встают в очередь и завершаются без ошибок взаимоблокировки. 28.04.2021
  • @Triyko использование блокировки U (с подсказкой UPDLOCK) менее блокирует, чем блокировку X, если вы хотите такой подход. 28.04.2021

  • 2

    Что здесь происходит: поскольку транзакции 1 выполняются на сериализуемом уровне изоляции, во время ожидания они сохраняют общую блокировку, полученную для статей таблицы. Таким образом, гарантируется, что условие «не существует» остается истинным до тех пор, пока транзакция не завершится. Транзакция 2 также получает блокировку общего доступа, что позволяет ей выполнить условие проверки существования. Затем с помощью оператора вставки транзакция 2 требует преобразовать общую блокировку в эксклюзивную блокировку, но ей приходится ждать, пока транзакция 1 удерживает общую блокировку. Когда транзакция 1 завершает ожидание, она также запрашивает преобразование в эксклюзивный режим => тупиковая ситуация, 1 транзакция должна быть завершена.

    25.04.2016
  • Это была именно моя проблема. Что я сделал, чтобы решить эту проблему, так это SELECT с явной монопольной блокировкой, и проблема исчезла. 08.11.2016
  • хорошее объяснение хорошего вопроса, а также приводит пример того, как обработка только одной таблицы также может привести к тупиковой ситуации. 19.06.2020

  • 3

    Я столкнулся с похожей проблемой и обнаружил, что:

    Из MSDN:

    SERIALIZABLE Указывает следующее:

    • Операторы не могут считывать данные, которые были изменены, но еще не зафиксированы другими транзакциями.
    • Никакие другие транзакции не могут изменять данные, которые были прочитаны текущей транзакцией, пока текущая транзакция не завершится.
    • Другие транзакции не могут вставлять новые строки со значениями ключей, попадающими в диапазон ключей, считываемых любыми инструкциями в текущей транзакции, пока текущая транзакция не завершится.

    Во втором пункте не говорится, что оба сеанса не могут установить общую блокировку, что приведет к тупиковой ситуации. Мы решили ее с подсказкой на SELECT.

    select * from articles WITH (UPDLOCK, ROWLOCK) where title like 'qwe'
    

    Не пробовал, сработает ли это в этом случае, но я думаю, вам придется заблокировать часть таблицы, поскольку строка еще не создана.

    06.07.2016
    Новые материалы

    Основы принципов S.O.L.I.D, Javascript, Git и NoSQL
    каковы принципы S.O.L.I.D? Принципы SOLID призваны помочь разработчикам создавать надежные, удобные в сопровождении приложения. мы видим пять ключевых принципов. Принципы SOLID были разработаны..

    Как настроить Selenium в проекте Angular
    Угловой | Селен Как настроить Selenium в проекте Angular Держите свое приложение Angular и тесты Selenium в одной рабочей области и запускайте их с помощью Mocha. В этой статье мы..

    Аргументы прогрессивного улучшения почти всегда упускают суть
    В наши дни в кругах веб-разработчиков много болтают о Progressive Enhancement — PE, но на самом деле почти все аргументы с обеих сторон упускают самую фундаментальную причину, по которой PE..

    Введение в Джанго Фреймворк
    Схема «работать умно, а не усердно» В этой и последующих статьях я познакомлю вас с тем, что такое фреймворк Django и как создать свое первое приложение с помощью простых и понятных шагов, а..

    Настольный ПК как «одно кольцо, чтобы править всеми» домашних компьютеров
    Вид после 9 месяцев использования С настольных компьютеров все началось, но в какой-то момент они стали «серверами», и мы все перешли на ноутбуки. В прошлом году я столкнулся с идеей настольных..

    Расширенные методы безопасности для VueJS: реализация аутентификации без пароля
    Руководство, которое поможет вам создавать безопасные приложения в долгосрочной перспективе Безопасность приложений часто упускается из виду в процессе разработки, потому что основная..

    стройный-i18следующий
    Представляем стройную оболочку для i18next. Эта библиотека, основанная на i18next, заключает экземпляр i18next в хранилище svelte и отслеживает события i18next, такие как languageChanged,..