Как различить восстанавливаемое и бескаскадное выполнение транзакций по моменту фиксации зависимых транзакций?

Как различить восстанавливаемое и бескаскадное выполнение транзакций по моменту фиксации зависимых транзакций?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

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

Исторический контекст

При конкурентном выполнении одна транзакция может зависеть от незакоммиченных изменений другой. Если первая успеет зафиксироваться, а вторая затем откатится из-за ошибки источника, восстановление становится сложным: зафиксированные данные уже основаны на отменённом состоянии.

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

Постановка проблемы

Пусть транзакция T2 прочитала значение, записанное T1. Если T2 зафиксируется до T1, а T1 затем откатится, база может содержать результат, вычисленный на данных, которых в действительности не должно существовать.

Если T2 ещё не зафиксировалась, её можно откатить вслед за T1. Но такой каскад увеличивает стоимость обработки ошибок и может затронуть цепочку других транзакций. Если зависимая транзакция уже зафиксирована, простой откат становится невозможным без нарушения атомарности.

Подробное решение

Расписание является восстанавливаемым, если для каждой зависимости чтения T2 от записи T1 выполняется правило: сначала фиксируется T1, затем T2. До фиксации T1 транзакция T2 может продолжать работу, но обязана ждать перед собственным COMMIT. Если T1 откатится, T2 также должна быть отменена.

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

Полезно отличать оба свойства от строгого расписания. При строгом выполнении до фиксации или отката T1 никто не может ни прочитать, ни перезаписать данные, изменённые T1. Это упрощает восстановление после сбоя и исключает не только каскадные откаты, но и грязные записи.

Иерархия обычно выглядит так: строгое выполнение строже бескаскадного, а бескаскадное строже восстанавливаемого. Конкретный уровень изоляции SQL не всегда напрямую называется этим термином: реализация может обеспечивать свойство блокировками, MVCC или их комбинацией. READ UNCOMMITTED потенциально допускает грязное чтение, тогда как уровни, запрещающие чтение незакоммиченных версий, обычно обеспечивают бескаскадное поведение для чтений.

Ситуация из практики

Сервис расчёта доступного остатка прочитал незакоммиченное уменьшение запаса из параллельной транзакции и записал на его основе резерв. Затем исходная транзакция откатилась. Резерв остался основанным на отменённом изменении — это пример каскадной зависимости с некорректным результатом при отсутствии восстанавливаемости.

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

Для расчёта бизнес-значимого остатка выбирают чтение только зафиксированных данных — через подходящий уровень изоляции или MVCC-реализацию СУБД. Это исключает зависимость от откатываемых изменений; цена решения — возможное повторное чтение, ожидание блокировки либо необходимость повторить транзакцию при конфликте.

Что кандидаты часто упускают

1. Вопрос: Может ли восстанавливаемое выполнение допускать чтение незакоммиченных данных?

Ответ: Да. Восстанавливаемость ограничивает порядок фиксации, но не запрещает сам факт чтения незакоммиченных изменений. Поэтому после отката T1 транзакция T2 должна быть отменена, если она ещё не зафиксирована. Запрет грязных чтений — это уже более сильное свойство, например бескаскадность.

2. Вопрос: Почему бескаскадное выполнение не обязательно означает отсутствие всех блокировок?

Ответ: Бескаскадность описывает допустимые зависимости чтения, а не способ их реализации. СУБД может добиться её блокировками, выдавая читателю доступ только после фиксации автора, или MVCC, показывая только зафиксированные версии. Поэтому одинаковое свойство расписания может иметь разную производительность и разное влияние на блокировки.

3. Вопрос: Что произойдёт при откате T1, если T2 прочитала её данные, но ещё не достигла фиксации?

Ответ: В восстанавливаемом расписании T2 нельзя просто оставить продолжать работу: её результаты основаны на отменённом состоянии. СУБД должна откатить T2 или повторно выполнить зависимую часть после устранения зависимости. Если таких транзакций несколько, возникает каскадный откат, поэтому практические системы часто запрещают грязные чтения и предпочитают бескаскадное или строгое выполнение.