# Уровни изоляции в PostgreSQL _MVCC и видимость · PostgreSQL Knowledge Base_ **TL;DR:** PostgreSQL различает три уровня изоляции. Read Committed (по умолчанию) берёт свежий снимок на каждый оператор. Repeatable Read берёт один снимок на транзакцию и держит его до конца. Serializable добавляет проверку, что транзакции можно выстроить в строгий порядок. Грязного чтения в PostgreSQL не бывает ни на одном уровне. Стандарт SQL описывает четыре уровня изоляции через аномалии, которые они запрещают. PostgreSQL реализует их строже стандарта: грязного чтения нет нигде, а Read Uncommitted ведёт себя как Read Committed. Реально различимы три уровня, и отличает их одно - **когда берётся снимок** (см. [snapshot](/courses/postgres/kb/snapshot.md)). ## Три уровня и их снимки | Уровень | Снимок | Что гарантирует сверх предыдущего | |---|---|---| | Read Committed | новый на каждый оператор | видит только зафиксированное | | Repeatable Read | один на транзакцию | повторное чтение неизменно | | Serializable | один на транзакцию + проверка | результат как при строгой очереди | **Read Committed** - уровень по умолчанию. Каждый оператор берёт свежий снимок, поэтому соседние SELECT в одной транзакции могут увидеть чужие свежие коммиты. Грязного (незафиксированного) он не покажет никогда. **Repeatable Read** фиксирует снимок один раз, в начале первого запроса, и держит до конца транзакции. Сколько раз ни перечитывай - картина та же. В PostgreSQL этот уровень заодно убирает фантомные строки, чего стандарт не требует. **Serializable** добавляет к снимку Repeatable Read проверку зависимостей между транзакциями. Подробности - в [serializable-ssi](/courses/postgres/kb/serializable-ssi.md). ## Какие аномалии где возможны | Аномалия | Read Committed | Repeatable Read | Serializable | |---|---|---|---| | грязное чтение | нет | нет | нет | | неповторяющееся чтение | да | нет | нет | | фантомное чтение | да | нет | нет | | аномалия сериализации | да | да | нет | Грязного чтения нет нигде - это особенность реализации PostgreSQL. Неповторяющееся и фантомное чтение отсекаются уже на Repeatable Read, потому что снимок заморожен. А вот **аномалия сериализации** (например, две транзакции, каждая читает то, что меняет другая) проходит даже на Repeatable Read - и ловится только на Serializable. ## Цена за строгость: ошибка сериализации За изоляцию выше Read Committed приходится платить. На Repeatable Read и Serializable конфликтующая запись не блокируется и не ждёт - транзакция **откатывается** с ошибкой `40001`: ``` ERROR: could not serialize access due to concurrent update ``` Это не сбой, а штатный сигнал «перепланируй и повтори транзакцию». Поэтому приложение на высоких уровнях изоляции обязано уметь повторять транзакцию при коде `40001`. Кто меняет строку первым - тот и выигрывает; остальные получают ошибку и идут на второй круг. ## Как переключать ```sql SHOW transaction_isolation; -- текущий уровень BEGIN ISOLATION LEVEL REPEATABLE READ; -- на одну транзакцию SET default_transaction_isolation = 'repeatable read'; -- на сессию ``` ## Команды ```sql SHOW transaction_isolation; ``` Уровень изоляции текущей транзакции ```sql BEGIN ISOLATION LEVEL REPEATABLE READ; ``` Открыть транзакцию с замороженным снимком на всю её длину ```sql BEGIN ISOLATION LEVEL SERIALIZABLE; ``` Самый строгий уровень: результат как при последовательном выполнении ## См. также - [Снимок данных (snapshot)](/courses/postgres/kb/snapshot.md) - [Serializable и SSI](/courses/postgres/kb/serializable-ssi.md) - [xmin, xmax и правила видимости](/courses/postgres/kb/xmin-xmax.md)