← Назад к вопросам
Как реализована надежность транзакции в postgresql?
1.8 Middle🔥 121 комментариев
#Базы данных (SQL)
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как реализована надежность транзакций в PostgreSQL?
ПостгресQL имеет одну из самых надёжных реализаций ACID транзакций. Давайте разберёмся, как она это достигает.
1. ACID — основа надежности
ACID — это четыре свойства надёжных транзакций:
- Atomicity (Атомарность) — транзакция либо полностью выполнится, либо полностью откатится
- Consistency (Согласованность) — БД переходит из одного консистентного состояния в другое
- Isolation (Изоляция) — транзакции не мешают друг другу
- Durability (Долговечность) — данные сохранены на диск
2. WAL (Write-Ahead Logging) — сердце надежности
ПостгресQL использует WAL для гарантии durability:
Данные в памяти (Shared Buffers)
↓
Записываем в WAL (диск) — это происходит ДО записи данных
↓
Данные в памяти изменены
↓
CHECKPOINT периодически записывает данные на диск
Механизм:
-- BEGIN транзакция
BEGIN;
-- Каждое изменение сначала идёт в WAL
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- PostgreSQL записывает WAL record на диск
-- Данные в памяти изменены, но на диск пока не пошли
COMMIT;
-- При коммите: fsync() гарантирует, что WAL на диске
-- Теперь данные безопасны, даже если сервер упадёт
3. Уровни изоляции (Isolation Levels)
ПостгресQL реализует 4 уровня изоляции согласно SQL стандарту:
-- 1. READ UNCOMMITTED (самый слабый)
-- В PostgreSQL это тоже самое что READ COMMITTED
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- 2. READ COMMITTED (по умолчанию)
-- Видит только закоммиченные данные
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
SELECT balance FROM accounts WHERE id = 1; -- Видит коммитные данные
COMMIT;
-- 3. REPEATABLE READ
-- Одна трансакция видит снимок БД на момент начала
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;
SELECT balance FROM accounts WHERE id = 1; -- Снимок 1
-- Другая транзакция меняет данные и коммитит
SELECT balance FROM accounts WHERE id = 1; -- Снимок остаётся прежним
COMMIT;
-- 4. SERIALIZABLE (самый строгий)
-- Изоляция как если бы транзакции выполнялись последовательно
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
4. MVCC (Multi-Version Concurrency Control)
ПостгресQL использует MVCC для читаемости без блокировок:
Все версии данных хранятся в памяти:
- xmin — XID, который создал эту версию
- xmax — XID, который удалил эту версию
Когда транзакция читает, она видит версии на основе своего XID
Пример MVCC:
-- Окно 1: Транзакция A
BEGIN; -- XID = 100
SELECT balance FROM accounts; -- Видит версии где xmin <= 100 и (xmax > 100 или NULL)
-- Окно 2: Транзакция B
BEGIN; -- XID = 101
UPDATE accounts SET balance = 500 WHERE id = 1;
-- Создаёт новую версию с xmin = 101
COMMIT;
-- Окно 1: Транзакция A
SELECT balance FROM accounts; -- Видит старую версию (xmin = 100)
-- Видит так же как раньше, потому что данные B'а не видны для A
COMMIT;
5. Блокировки для конкурентности
ПостгресQL использует различные типы блокировок:
-- SELECT — не требует блокировки (MVCC)
SELECT * FROM accounts WHERE id = 1;
-- SELECT FOR UPDATE — эксклюзивная блокировка
BEGIN;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;
-- Другие транзакции ждут, пока эта закончится
-- SELECT FOR SHARE — совместная блокировка
SELECT * FROM accounts WHERE id = 1 FOR SHARE;
-- Несколько транзакций могут иметь FOR SHARE
-- Deadlock detection
BEGIN; -- Транзакция 1
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
-- Другая транзакция пытается
SELECT * FROM accounts WHERE id = 2 FOR UPDATE;
-- Если транзакция 2 пытается 1, а 2 пытается 1 — deadlock
-- PostgreSQL обнаружит и откатит одну из них
-- ERROR: deadlock detected
6. Механизм COMMIT
# Python пример с psycopg2
import psycopg2
conn = psycopg2.connect('dbname=test')
cur = conn.cursor()
try:
# BEGIN транзакция
cur.execute('UPDATE accounts SET balance = balance - 100 WHERE id = 1')
cur.execute('UPDATE accounts SET balance = balance + 100 WHERE id = 2')
# COMMIT — важный момент
conn.commit()
# PostgreSQL:
# 1. Записывает COMMIT record в WAL
# 2. Запускает fsync() чтобы убедиться WAL на диске
# 3. Изменяет видимость для других транзакций
except Exception as e:
conn.rollback() # ROLLBACK
# PostgreSQL откатит все изменения
print(f'Error: {e}')
finally:
cur.close()
conn.close()
7. Recovery после сбоя
Сервер упал
↓
ПостгресQL восстанавливается из WAL
↓
Откатывает незакоммиченные транзакции (undo from WAL)
↓
Повторяет закоммиченные транзакции (redo from WAL)
↓
Проверяет консистентность и запускается
8. Практический пример надежности
-- Сценарий: перевод денег между счетами
BEGIN TRANSACTION;
UPDATE accounts
SET balance = balance - 100
WHERE id = 1;
-- Если произойдёт ошибка ДО следующей строки, изменение откатится
UPDATE accounts
SET balance = balance + 100
WHERE id = 2;
COMMIT; -- Обе операции коммитятся вместе
-- Если сервер упадёт:
-- - До COMMIT: обе операции откатятся из WAL
-- - После COMMIT: обе операции восстановятся из WAL
-- Никогда не будет ситуации когда отправили, но не получили!
9. Явное управление изоляцией
import psycopg2
from psycopg2.extensions import ISOLATION_LEVEL_SERIALIZABLE
conn = psycopg2.connect('dbname=test')
conn.set_isolation_level(ISOLATION_LEVEL_SERIALIZABLE)
cur = conn.cursor()
# Все транзакции будут SERIALIZABLE
cur.execute('SELECT * FROM accounts')
conn.commit()
10. Синхронная репликация
Первичный сервер
↓ (отправляет WAL)
Вторичный сервер (реплика)
↓ (получает и подтверждает)
Первичный получает confirmation
↓
Клиент получает COMMIT успешно
11. Проверка целостности
-- Проверить состояние транзакций
SELECT * FROM pg_stat_activity;
-- Смотреть блокировки
SELECT * FROM pg_locks;
-- Информация о WAL
SHOW wal_level; -- replica, logical
SHOW fsync; -- on/off
Вывод
ПостгресQL достигает надёжности через:
- WAL (Write-Ahead Logging) — гарантирует, что коммитные данные на диске
- MVCC — позволяет читать без блокировок
- ACID изоляция — четыре уровня для разных требований
- Блокировки — управляют конкурентным доступом
- Recovery механизм — восстанавливается после сбоев
- Синхронная репликация — копирует данные на другие серверы
Это делает PostgreSQL одной из самых надёжных баз данных с гарантией ACID.