Isolation levels

SQL стандарт (ANSI SQL-92) описывает 4 уровня изоляции транзакций. Определяют какие аномалии возможны при параллельном выполнении.

Аномалии

АномалияЧто
Dirty readчтение незакоммиченных данных
Non-repeatable readдве одинаковые SELECT в одной tx дают разные значения (кто-то UPDATE закоммитил)
Phantom readдве одинаковые SELECT дают разное число строк (кто-то INSERT/DELETE закоммитил)
Write skewдве tx читают одни данные, пишут не пересекающиеся, нарушают инвариант
Lost updateдве tx читают, обе изменяют, второй перезаписывает первый

Уровни по стандарту

УровеньDirtyNon-repeatPhantom
READ UNCOMMITTEDвозможенвозможенвозможен
READ COMMITTED-возможенвозможен
REPEATABLE READ--возможен*
SERIALIZABLE---

*В PostgreSQL и InnoDB REPEATABLE READ фактически не имеет phantom.

Реальные дефолты

БДDefault
PostgreSQLREAD COMMITTED
MySQL InnoDBREPEATABLE READ
OracleREAD COMMITTED
SQL ServerREAD COMMITTED
CockroachDBSERIALIZABLE (единственный)

READ COMMITTED (PG default)

Каждый оператор видит свежий snapshot. Две SELECT подряд могут вернуть разное.

T1: BEGIN
T1: SELECT balance FROM acc WHERE id=1 → 100
                                              T2: UPDATE acc SET balance=200 WHERE id=1
                                              T2: COMMIT
T1: SELECT balance FROM acc WHERE id=1 → 200   ← non-repeatable read
T1: COMMIT

REPEATABLE READ

Одна snapshot на всю транзакцию. Две SELECT дадут одно значение.

T1: BEGIN ISOLATION LEVEL REPEATABLE READ
T1: SELECT balance → 100
                             T2: UPDATE, COMMIT
T1: SELECT balance → 100   ← видим старое
T1: COMMIT

SERIALIZABLE

Транзакции выполняются как будто последовательно. Защита от всего, включая write skew.

PostgreSQL реализация — SSI (Serializable Snapshot Isolation, Michael Cahill 2008). Работает через отслеживание read/write dependencies. При коммите — если найден риск нарушения serializable — откат одной из tx.

T1 → ERROR: could not serialize access due to read/write dependencies among transactions
# приложение должно ретраить

SELECT ... FOR UPDATE

Явная блокировка row без повышения isolation. Часто проще чем SERIALIZABLE.

BEGIN;
SELECT balance FROM acc WHERE id=1 FOR UPDATE;
-- никто другой не UPDATE эту строку до COMMIT
UPDATE acc SET balance=balance-100 WHERE id=1;
COMMIT;

Snapshot vs Serializable

SI (snapshot isolation) не эквивалентен SERIALIZABLE. Уязвим к write skew. Oracle SERIALIZABLE на самом деле — SI, не настоящий SERIALIZABLE. PG — настоящий SERIALIZABLE (SSI).

См. также

← на главную