← Назад к вопросам
Какие знаешь способы изоляции транзакций в PostgreSQL?
3.0 Senior🔥 161 комментариев
#Архитектура и паттерны#Базы данных (SQL)
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Уровни изоляции транзакций в PostgreSQL
Изоляция транзакций — это ключевое понятие в ACID свойстве баз данных. PostgreSQL поддерживает четыре стандартных уровня изоляции SQL, каждый из которых защищает от различных проблем параллельного доступа.
1. READ UNCOMMITTED (Чтение незафиксированных данных)
Характеристика: Самый низкий уровень изоляции.
from django.db import transaction
with transaction.atomic():
user = User.objects.get(id=1)
2. READ COMMITTED (Чтение зафиксированных данных)
Характеристика: Уровень по умолчанию в PostgreSQL. Транзакция видит только зафиксированные данные.
from django.db import transaction
@transaction.atomic(using='default', durable=False)
def transfer_money(account_from_id, account_to_id, amount):
account_from = Account.objects.select_for_update().get(id=account_from_id)
account_to = Account.objects.get(id=account_to_id)
if account_from.balance >= amount:
account_from.balance -= amount
account_from.save()
account_to.balance += amount
account_to.save()
3. REPEATABLE READ (Повторяемое чтение)
Характеристика: Используется снимок состояния БД на начало транзакции. Все SELECT в транзакции видят одни и те же данные.
from django.db import transaction
@transaction.atomic(isolation=transaction.ISOLATION_SERIALIZABLE)
def update_with_repeatable_read():
product = Product.objects.get(id=1)
print(f'Первый запрос: {product.price}')
product_again = Product.objects.get(id=1)
print(f'Второй запрос: {product_again.price}')
4. SERIALIZABLE (Сериализуемость)
Характеристика: Самый высокий уровень. Транзакции выполняются так, будто идут последовательно, а не параллельно.
from django.db import transaction
@transaction.atomic(isolation=transaction.ISOLATION_SERIALIZABLE)
def count_products_and_check():
count = Product.objects.count()
new_product = Product.objects.create(name='New')
5. Django ORM + уровни изоляции
from django.db import transaction, connections
@transaction.atomic(isolation=transaction.ISOLATION_REPEATABLE_READ)
def safe_operation():
order = Order.objects.select_for_update().get(id=1)
order.status = 'processing'
order.save()
with transaction.atomic(isolation=transaction.ISOLATION_SERIALIZABLE):
pass
conn = connections['default']
with conn.cursor() as cursor:
cursor.execute('SHOW transaction_isolation')
print(cursor.fetchone())
6. SELECT FOR UPDATE — явная блокировка
from django.db import transaction
@transaction.atomic
def transfer_money_safe(account_from_id, account_to_id, amount):
account_from = Account.objects.select_for_update(skip_locked=True).get(
id=account_from_id
)
try:
account_to = Account.objects.select_for_update(nowait=True).get(
id=account_to_id
)
except transaction.TransactionManagementError:
print('Строка заблокирована другой транзакцией')
if account_from.balance >= amount:
account_from.balance -= amount
account_from.save()
account_to.balance += amount
account_to.save()
7. Явное управление уровнем в сыром SQL
from django.db import connection
def raw_transaction_with_isolation():
with connection.cursor() as cursor:
cursor.execute('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE')
cursor.execute('BEGIN')
try:
cursor.execute('SELECT * FROM users WHERE id = %s', [1])
user = cursor.fetchone()
cursor.execute('UPDATE users SET active = true WHERE id = %s', [1])
cursor.execute('COMMIT')
except Exception as e:
cursor.execute('ROLLBACK')
raise
8. Retry логика для SERIALIZABLE
from django.db import transaction
import time
def retry_on_serialization_error(max_retries=3, delay=0.1):
def decorator(func):
def wrapper(*args, **kwargs):
for attempt in range(max_retries):
try:
with transaction.atomic(isolation=transaction.ISOLATION_SERIALIZABLE):
return func(*args, **kwargs)
except transaction.TransactionManagementError as e:
if 'serialization failed' in str(e) and attempt < max_retries - 1:
time.sleep(delay * (2 ** attempt))
continue
raise
return wrapper
return decorator
@retry_on_serialization_error()
def critical_operation():
pass
Мои рекомендации на практике
- По умолчанию: READ COMMITTED достаточно для 99% случаев
- Когда нужна консистентность: REPEATABLE READ для отчётов и аналитики
- Критичные операции: SERIALIZABLE + retry логика
- Блокировки: SELECT FOR UPDATE для операций с деньгами и инвентарём
- Избегай deadlock-ов: Всегда блокируй строки в одном порядке