Serializable гарантує, що результат паралельних транзакцій буде таким, ніби вони виконувалися по черзі в якомусь порядку. Жодних аномалій паралельності - навіть тих, від яких не рятує Repeatable Read.
Класична аномалія, яку ловить лише Serializable - write skew:
-- У лікарні має чергувати хоча б один лікар. Чергують двоє.
-- Транзакція A: -- Транзакція B:
SELECT count(*) FROM doctors SELECT count(*) FROM doctors
WHERE on_call; -- 2 WHERE on_call; -- 2
UPDATE doctors SET on_call = false UPDATE doctors SET on_call = false
WHERE id = 1; WHERE id = 2;
COMMIT; COMMIT;
-- Результат: не чергує ніхто
Кожна транзакція окремо коректна, а разом вони порушили правило. На Repeatable Read обидві закомітяться.
Як PostgreSQL це реалізує - SSI (Serializable Snapshot Isolation): транзакції не блокують одна одну, а база відстежує залежності між тим, що кожна прочитала й записала. Якщо виявлено небезпечний цикл залежностей, одна з транзакцій отримує помилку:
ERROR: could not serialize access due to read/write dependencies among transactions
SQLSTATE 40001
Помилка серіалізації - не збій, а частина контракту. Застосунок мусить повторити всю транзакцію з початку:
DB::transaction(function () {
// ...
}, attempts: 3); // Laravel повторить при deadlock чи serialization failure
Ціна Serializable:
- Повтори транзакцій - логіка має бути ідемпотентною до коміту (без листів і HTTP-запитів усередині).
- Додаткові накладні витрати на відстеження залежностей.
- Більше відкатів під високою конкуренцією.
Коли обирати: складні бізнес-правила, що залежать від кількох рядків (бронювання, ліміти, інваріанти «хоча б один / не більше N»), і коли розставляти блокування вручну складно. Для простих випадків часто достатньо атомарного UPDATE чи SELECT ... FOR UPDATE.