Параллельные транзакции чтения и обновления с уровнями изоляции Repeatable Read в SQL Server

Спецификация для уровня изоляции Repeatable-Read определяет, что транзакция с этим IL не позволит другим транзакциям обновлять любые строки, прочитанные этой транзакцией, до завершения этой транзакции. Таким образом, повторяющиеся чтения гарантированы.

Рассмотрим следующий порядок операций для двух параллельных транзакций T1 и T2, в обеих из которых используется IL с повторяемым чтением:

  1. T1: чтение строки
  2. T2: прочитать строку
  3. T1: обновить строку
  4. T2: обновить строку

Я думаю, что обновление на шаге 3 нарушит спецификацию уровня изоляции, так как T2 будет читать другое значение, если он снова прочитает строку. Обратное можно сказать об обновлении на шаге 4.

Итак, какие различные варианты доступны для реляционных СУБД в целом для разрешения этого конфликта? В частности, как это обрабатывается в SQL Server 2017+? Приведет ли это к взаимоблокировке, поскольку ни одна из транзакций не может завершить свои операции? Или будет отменена одна транзакция? Я видел, что в SQL Server предотвращены потерянные обновления. Что это означает для разрешения этого конкретного случая?

Я просмотрел ответы на эти вопросы: Повторяемая таблица совместимости чтения и блокировки Повторяемое чтение - правильно ли я понимаю? повторяющееся чтение и вторая проблема с потерянными обновлениями Уровень изоляции MySQL Repeatable Read и явление Lost Update

И хотя последний задает аналогичный вопрос, но не содержит никакой конкретной информации о том, как СУБД, которые предотвращают потерю обновлений для txs с этим уровнем изоляции, обрабатывают этот случай.


person djaxxon    schedule 29.01.2020    source источник
comment
Вопросы SO редко бывают такими же хорошими, как фактическая документация по базе данных. Ссылки также указывают на совершенно разные вещи, некоторые из которых говорят о MVCC, а не о повторяемом чтении. Без MVCC нет потерянных обновлений. Обновление означает чтение, поэтому оба потока начинаются с блокировки S(hared). В этом примере возникла тупиковая ситуация, поскольку обе транзакции хотят обновить блокировку S до исключительной блокировки. Однако, как правило, этого не происходит, поскольку большинство запросов читаются, а не обновляются массово.   -  person Panagiotis Kanavos    schedule 29.01.2020
comment
Вот почему следует избегать таких сценариев. Нет необходимости в отдельных запросах READ и UPDATE, используйте один UPDATE .. SELECT. Это будет выполняться как одна атомарная операция, устанавливающая соответствующие блокировки за один шаг.   -  person Panagiotis Kanavos    schedule 29.01.2020
comment
@PanagiotisKanavos Спасибо за ваш комментарий и предложение. Я рассматривал только отдельные операторы READ и UPDATE, поскольку я ограничен использованием Entity Framework в качестве клиента SQL. Похоже, что взаимоблокировка сама по себе является механизмом, с помощью которого здесь предотвращается потеря обновления, и проблемы лучше избежать, каким-то образом используя атомарную операцию, как вы говорите.   -  person djaxxon    schedule 29.01.2020