TGViewer
Женя Янченко Женя Янченко @jane_yanchenko · 5.51K subscribers
Post #98 1.42K
Уровень изоляции транзакций Repeatable Read

Прошлый раз мы разобрали уровень Read Commited, который защищает от «грязных» чтений и «грязных» записей. Однако на уровне Read Commited возможно возникновение других ошибок конкурентного доступа.

📌 Неповторяемое чтение (non-repeatable read)

На первой картинке к посту изображена аномалия неповторяемого чтения (non-repeatable read). Или более редкий термин — асимметрия чтения (read skew).

Кратко схему аномалии non-repeatable read я бы описала так:

➡️ Первая транзакция делает SELECT
➡️ Другая делает UPDATE и коммит
➡️ Первая транзакция делает SELECT и видит несоответствие с первым чтением

То есть первая транзакция получила неповторяемое чтение.

В ситуации с картинки это временная проблема, которая решится после обновления страницы. Однако в некоторых ситуациях подобные несоответствия недопустимы.

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

Ее идея состоит в том, что каждая из транзакций читает данные из согласованного снимка состояния БД, то есть видит данные, которые были зафиксированы в базе на момент ее начала этой транзакции. Даже если данные затем были изменены другой транзакцией, каждая транзакция видит только старые данные — снимок состояния, «замороженного» в определенный момент времени.

Изоляция снимков состояния используется в PostgreSQL, MySQL с InnoDB, Oracle, SQL Server.

Реализация изоляции снимков состояния

Для реализации изоляции снимков состояния базы применяют обобщение механизма, используемого для предотвращения «грязных» чтений: БД хранит несколько различных зафиксированных версий объекта, поскольку разным транзакциям может понадобиться состояние базы на различные моменты времени. Этот метод получил название многоверсионного управления конкурентным доступом (multiversion concurrency control — MVCC).

В самом начале выполнения транзакция получает уникальный, монотонно возрастающий идентификатор (txid). В каждой строке таблицы есть поле created_by, содержащее идентификатор транзакции, вставившей эту строку в таблицу. Также в каждой строке таблицы есть поле deleted_by, изначально пустое. Если транзакция удаляет строку, то строка помечается для удаления путем установки deleted_by = txid запросившей
удаление транзакции. В дальнейшем, когда уже никакая транзакция точно не обратится к удаленным данным, процесс сборки мусора БД удалит все помеченные для удаления строки и освободит занимаемое ими место.

Обновление превращается внутри базы данных в удаление и создание.

📌 Потерянное обновление (lost update)

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

Для предотвращения потерянных обновлений можно использовать:

✅ атомарные записи

UPDATE accounts SET balance = balance + 100
WHERE id = 123;


✅ явные блокировки

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

BEGIN TRANSACTION;

SELECT * FROM items WHERE category = 'robot' FOR UPDATE;

-- Делаем какие-то проверки, после чего обновляем возвращенные SELECT-ом данные

UPDATE items SET price = '100.00' WHERE id = 123;

COMMIT;


Предложение FOR UPDATE указывает базе блокировать все возвращенные запросом строки.

✅ автоматическое обнаружение потери обновлений

PostgreSQL на уровне изоляции Repeatable Read (и другие БД, кроме MySQL) обеспечивают автоматическое обнаружение потери обновлений и прерывание проблемных транзакций.

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

#кабанчик #сисдиз
  • 👍 12
  • 🔥 4
  • ❤‍🔥 2
  • ❤ 2
  • 🐳 1
More from @jane_yanchenko
  1. Sep 30, 2026Представьте ситуацию. Дисклеймер: пример вымышленный, проблема реально встречающаяся 🐤 Вы…
  2. Sep 25, 2026В прошлой жизни, когда я была менеджером проектов, одним из первых мест работы у меня был…
  3. Sep 23, 2026Куда пропало обращение - развязка В прошлом посте у нас загадочно пропало обращение 58122.…
  4. Sep 23, 2026Куда пропало обращение Однажды от руководителя техподдержки пришло письмо, суть которого с…
  5. Sep 21, 2026🔗 Подборка постов про Кафку Как обещала на стриме, собрала посты про Кафку в удобное огла…
  6. Sep 21, 2026🎞 Готова запись стрима про Кафку: https://youtu.be/2aRKsD-MWDA Большое спасибо всем, кто…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →