Зачем нужны низкие уровни изоляции в БД?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Низкие уровни изоляции в БД
Уровни изоляции (isolation levels) контролируют, как конкурирующие транзакции видят изменения друг друга. Низкие уровни позволяют большую конкурентность, но создают проблемы с консистентностью.
Иерархия уровней изоляции
OT СЛАБОГО К СИЛЬНОМУ:
1. Dirty Read (READ UNCOMMITTED) ← Низкие уровни
2. Non-Repeatable Read (READ COMMITTED)
3. Phantom Read (REPEATABLE READ)
4. Serializable (SERIALIZABLE) ← Высокие уровни
1. READ UNCOMMITTED (самый слабый)
Транзакция может читать НЕПОДТВЕРЖДЁННЫЕ изменения (грязное чтение).
Транзакция 1: Транзакция 2:
BEGIN;
UPDATE users
SET balance = 500
WHERE id = 1;
BEGIN;
SELECT balance FROM users WHERE id = 1;
→ Прочитала 500! (не подтверждено)
ROLLBACK; ← Откатилась!
SELECT balance FROM users WHERE id = 1;
→ Теперь 1000 (откатилась, но мы видели 500)
Проблемы: Грязные чтения Используется: Почти никогда (слишком опасно)
2. READ COMMITTED
Транзакция видит только подтверждённые данные, но возможны non-repeatable reads.
Транзакция 1: Транзакция 2:
BEGIN;
SELECT balance FROM users
WHERE id = 1;
→ balance = 1000
BEGIN;
UPDATE users SET balance = 500 WHERE id = 1;
COMMIT;
SELECT balance FROM users
WHERE id = 1;
→ balance = 500! (изменилось в одной транзакции)
Проблемы: Non-repeatable reads (один запрос → разные результаты) Используется: PostgreSQL по умолчанию, часто достаточно
3. REPEATABLE READ
В рамках транзакции одни и те же данные всегда одинаковые, но возможны phantom reads.
Транзакция 1: Транзакция 2:
BEGIN;
SELECT * FROM users
WHERE age > 18;
→ 10 пользователей
BEGIN;
INSERT INTO users (name, age)
VALUES ('Alice', 25);
COMMIT;
SELECT * FROM users
WHERE age > 18;
→ 11 пользователей! (фантомные строки)
Проблемы: Phantom reads (новые строки появляются) Используется: MySQL InnoDB по умолчанию, хороший баланс
4. SERIALIZABLE (самый сильный)
Транзакции выполняются как если бы они выполнялись по одной (последовательно), без конкурентности.
Транзакция 1: Транзакция 2:
BEGIN;
SELECT * FROM users;
BEGIN;
UPDATE users SET active = true;
← Ждёт! (блокируется)
COMMIT;
← Теперь может выполняться
OK
Проблемы: Очень медленно (много блокировок) Используется: Только когда абсолютная консистентность критична
Зачем нужны НИЗКИЕ уровни?
1. Производительность
Низкие уровни позволяют более высокую конкурентность и пропускную способность:
# При READ COMMITTED
# Транзакция 1 читает строку X
# Транзакция 2 может сразу же обновить строку X
# Оба выполняются быстро
# При SERIALIZABLE
# Если Транзакция 1 читает X
# Транзакция 2 ЖДЁТ, пока Транзакция 1 закончит
# Общее время выполнения: сумма времени
2. Масштабируемость
Высокие нагрузки требуют низких уровней:
-- Веб-приложение с 1000 одновременных юзеров
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- SERIALIZABLE взорвёт БД от количества блокировок
3. Практические сценарии
READ COMMITTED — для большинства приложений:
# Интернет-магазин
BEGIN;
SELECT stock FROM products WHERE id = 123;
-- Одна транзакция прочитала stock = 10
-- Другая транзакция уменьшила его до 5
-- Первая увидит 5 при следующем запросе
-- Это нормально для магазина!
COMMIT;
REPEATABLE READ — для транзакций, требующих консистентности данных:
# Банковский перевод
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
balance_from = SELECT balance FROM accounts WHERE id = 1; # 1000
balance_to = SELECT balance FROM accounts WHERE id = 2; # 500
if balance_from >= 100:
UPDATE accounts SET balance = balance_from - 100 WHERE id = 1;
UPDATE accounts SET balance = balance_to + 100 WHERE id = 2;
COMMIT;
Проблема: когда читаешь разные значения?
# Non-repeatable read
BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;
name = SELECT name FROM users WHERE id = 1; # "Alice"
# Другая транзакция обновила: UPDATE users SET name = "Bob" WHERE id = 1;
name = SELECT name FROM users WHERE id = 1; # "Bob" — изменилось!
Решение: используй REPEATABLE READ если нужна стабильность.
Практическое руководство
import psycopg2
# PostgreSQL
conn = psycopg2.connect("dbname=mydb")
# Установить уровень изоляции
conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED)
# или
conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_REPEATABLE_READ)
# или
conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE)
# SQL
cursor = conn.cursor()
cursor.execute("""
BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT * FROM users;
COMMIT;
""")
Таблица выбора
| Ситуация | Уровень | Причина |
|---|---|---|
| Веб-приложение (обычное) | READ COMMITTED | Баланс скорости и консистентности |
| Финансовые операции | REPEATABLE READ | Нужна стабильность данных |
| Критичные платежи | SERIALIZABLE | Абсолютная консистентность |
| Аналитика, отчёты | READ UNCOMMITTED | Скорость важнее точности (редко) |
Низкие уровни изоляции — необходимо зло для балансировки между консистентностью и производительностью.