← Назад к вопросам
Что такое уровень изолированности транзакции в БД?
2.0 Middle🔥 121 комментариев
#Базы данных (SQL)
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Что такое уровень изолированности транзакции в БД?
Уровень изолированности (isolation level) определяет, как транзакции взаимодействуют между собой при одновременном доступе к одним и тем же данным. Это одна из четырёх свойств ACID транзакций.
ACID в транзакциях
- Atomicity — атомарность (всё или ничего)
- Consistency — консистентность (данные остаются валидными)
- Isolation — изолированность (транзакции не мешают друг другу)
- Durability — долговечность (данные сохраняются)
Проблемы конкурентности без изоляции
1. Dirty Read (грязное чтение)
Транзакция 1: Транзакция 2:
BEGIN BEGIN
UPDATE balance=100
SELECT balance → читает 100!
ROLLBACK (Данные откатились! Прочитала грязные данные)
2. Non-Repeatable Read (неповторяемое чтение)
Транзакция 1: Транзакция 2:
BEGIN
SELECT balance → 50 BEGIN
UPDATE balance=100
COMMIT
SELECT balance → 100 (Одна транзакция, разные результаты!)
3. Phantom Read (фантомное чтение)
Транзакция 1: Транзакция 2:
BEGIN
SELECT * FROM users BEGIN
WHERE age > 18 → 5 rows INSERT INTO users VALUES (..., age=20)
COMMIT
SELECT * FROM users
WHERE age > 18 → 6 rows (Новая строка появилась!)
4. Lost Update (потерянное обновление)
Транзакция 1: Транзакция 2:
SELECT balance → 100
SELECT balance → 100
balance = 100 + 50 = 150
UPDATE balance=150
balance = 100 + 30 = 130
UPDATE balance=130
Витоге: balance=130 (Обновление T1 потеряно!)
Четыре уровня изолированности (SQL Standard)
1. READ UNCOMMITTED (самый слабый)
Позволяет: грязное чтение
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN;
SELECT * FROM users; -- Может читать незакоммиченные данные
COMMIT;
Проблемы:
- Dirty reads ✓
- Non-repeatable reads ✓
- Phantom reads ✓
- Lost updates ✓
Использование: Редко, очень небезопасный
2. READ COMMITTED
Позволяет: только коммиченные данные
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
SELECT * FROM users; -- Читает только закоммиченные данные
COMMIT;
Проблемы:
- ✗ Dirty reads
- ✓ Non-repeatable reads
- ✓ Phantom reads
- ✓ Lost updates
Использование: По умолчанию в PostgreSQL, MySQL (InnoDB)
3. REPEATABLE READ
Позволяет: Одна транзакция видит снимок данных
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;
SELECT * FROM users; -- Снимок в начале транзакции
-- Другие транзакции не смогут изменить эти строки
SELECT * FROM users; -- Тот же результат
COMMIT;
Проблемы:
- ✗ Dirty reads
- ✗ Non-repeatable reads
- ✓ Phantom reads
- ✗ Lost updates
Использование: По умолчанию в MySQL (InnoDB)
4. SERIALIZABLE (самый строгий)
Позволяет: Транзакции работают как будто последовательно
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT * FROM users; -- Полная изоляция
-- Всё как в однопоточном мире
COMMIT;
Проблемы:
- ✗ Dirty reads
- ✗ Non-repeatable reads
- ✗ Phantom reads
- ✗ Lost updates
Недостаток: Может сильно снизить производительность
Сравнительная таблица
| Уровень | Dirty Read | Non-Rep. Read | Phantom Read | Производительность |
|---|---|---|---|---|
| READ UNCOMMITTED | ✓ | ✓ | ✓ | Очень быстро |
| READ COMMITTED | ✗ | ✓ | ✓ | Быстро |
| REPEATABLE READ | ✗ | ✗ | ✓ | Средне |
| SERIALIZABLE | ✗ | ✗ | ✗ | Медленно |
Практический пример на PostgreSQL
READ COMMITTED (по умолчанию)
Терминал 1:
BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT balance FROM accounts WHERE id=1; -- 1000
Терминал 2:
BEGIN TRANSACTION;
UPDATE accounts SET balance=500 WHERE id=1;
COMMIT;
Терминал 1 (после коммита в T2):
SELECT balance FROM accounts WHERE id=1; -- 500 (изменилось!)
COMMIT;
REPEATABLE READ
Терминал 1:
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT balance FROM accounts WHERE id=1; -- 1000
Терминал 2:
BEGIN TRANSACTION;
UPDATE accounts SET balance=500 WHERE id=1;
COMMIT;
Терминал 1:
SELECT balance FROM accounts WHERE id=1; -- 1000 (не изменилось!)
COMMIT;
Использование в Django/Python
Django
from django.db import transaction
# Явное задание уровня изолированности
with transaction.atomic():
user = User.objects.get(id=1)
user.balance -= 100
user.save()
SQLAlchemy
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
engine = create_engine('postgresql://...')
Session = sessionmaker(bind=engine)
# Уровень изолированности (PostgreSQL)
session = Session()
conn = engine.raw_connection()
conn.set_isolation_level(1) # READ COMMITTED
Psycopg2
import psycopg2
conn = psycopg2.connect('...')
conn.set_isolation_level(
psycopg2.extensions.ISOLATION_LEVEL_REPEATABLE_READ
)
Когда использовать какой уровень
READ COMMITTED
- Стандартный выбор
- Большинство случаев
- Хороший баланс между безопасностью и производительностью
REPEATABLE READ
- Когда нужна консистентность в одной транзакции
- Финансовые операции
- Отчёты, которые не должны меняться внутри расчёта
SERIALIZABLE
- Очень критичные данные
- Когда невозможно использовать оптимистичные блокировки
- Редко в production
Решение проблем конкурентности
1. Оптимистичная блокировка (version field)
class Product(models.Model):
name = models.CharField(max_length=100)
version = models.IntegerField(default=1)
# В коде
product = Product.objects.get(id=1)
product.name = 'New Name'
affected = Product.objects.filter(
id=product.id, version=product.version
).update(name=product.name, version=product.version+1)
if not affected:
raise ConcurrencyError('Product was updated elsewhere')
2. Пессимистичная блокировка (SELECT FOR UPDATE)
from django.db.models import F
with transaction.atomic():
product = Product.objects.select_for_update().get(id=1)
product.name = 'New Name'
product.save()
Итоги
- Уровень изолированности — настройка БД, как разные транзакции видят друг друга
- 4 уровня: READ UNCOMMITTED → READ COMMITTED → REPEATABLE READ → SERIALIZABLE
- Компромисс: больше изоляции = ниже производительность
- В 99% случаев используй READ COMMITTED (по умолчанию)
- Для критичных данных используй REPEATABLE READ или явные блокировки