lesson ── postgres-labs ── ~25 мин ── 5 шагов
Воспроизведи неповторяющееся чтение на уровне по умолчанию, а потом поймай ошибку сериализации на Serializable - настоящий перекос записи. Перед каждым шагом предсказывай: изменится ли чтение, пройдёт ли коммит.
интерактивный sandbox
Поднимется контейнер postgreslab/postgres-base с PostgreSQL 17 и psql. В браузере откроется терминал, база lab уже настроена. Каждый шаг проверяется автоматически. Сеть air-gapped, наружу контейнер не ходит.
stack ── PostgreSQL 17 · psql · 1 GB RAM · air-gapped · самоуничтожается через 45 мин простоя
Во вкладке A (уровень по умолчанию Read Committed) прочитай бронь и запомни значение.
SELECT total FROM bookings WHERE book_ref = '000002';
✓ Исходное значение брони - 102.00.
Перейди во вкладку B, измени ту же бронь и зафиксируй.
UPDATE bookings SET total = 500 WHERE book_ref = '000002';
COMMIT;
✓ B изменила бронь и зафиксировала - теперь 500.00.
Вернись во вкладку A и прочитай ту же бронь ещё раз. Предскажи: то же значение или новое? На Read Committed снимок берётся на каждый оператор.
SELECT total FROM bookings WHERE book_ref = '000002';
Это и есть неповторяющееся чтение: два одинаковых запроса дали разный ответ.
✓ Чтение поменялось: неповторяющееся чтение на Read Committed.
Во вкладке A создай таблицу дежурных - оба на смене.
CREATE TABLE oncall (name text, on_call boolean);
INSERT INTO oncall VALUES ('alice', true), ('bob', true);✓ Двое на дежурстве - готово к опыту с перекосом записи.
Теперь воспроизведи перекос записи. Делай строго по порядку, переключая вкладки.
Вкладка A:
BEGIN ISOLATION LEVEL SERIALIZABLE;
SELECT count(*) FROM oncall WHERE on_call; -- видит 2
UPDATE oncall SET on_call = false WHERE name = 'alice';
Вкладка B:
BEGIN ISOLATION LEVEL SERIALIZABLE;
SELECT count(*) FROM oncall WHERE on_call; -- тоже видит 2
UPDATE oncall SET on_call = false WHERE name = 'bob';
Вкладка A:
COMMIT; -- проходит
Вкладка B:
COMMIT; -- ошибка 40001: could not serialize access due to read/write dependencies
Каждый снял своего, но движок увидел опасную зависимость и откатил B. Предскажи: сколько дежурных осталось на смене?
Перекос записи: оба прочитали то, что менял другой. Serializable жертвует одной транзакцией.
✓ На дежурстве остался один - Serializable не дал перекосу пройти.
На Read Committed повторное чтение увидело чужой коммит - неповторяющееся чтение. На Serializable перекос записи пойман: A закоммитилась, B получила 40001, на дежурстве остался ровно один. Высокий уровень изоляции требует повтора по 40001.
команды
BEGIN ISOLATION LEVEL SERIALIZABLE;транзакция с гарантией сериализуемостиSHOW transaction_isolation;текущий уровень изоляцииконцепции