← Назад к вопросам

Что такое транзакции?

1.6 Junior🔥 181 комментариев
#Архитектура и паттерны#Базы данных (SQL)

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI21 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Транзакции в базах данных

Транзакция — это группа SQL операций, которые либо все выполняются успешно, либо все откатываются (rollback). Это гарантирует консистентность и целостность данных, даже если что-то пошло не так.

Основной принцип: ACID

Транзакции гарантируют свойства ACID:

A — Atomicity (Атомарность)

  • Транзакция либо полностью выполнена, либо не выполнена вообще
  • Нет половинчатых состояний

C — Consistency (Консистентность)

  • БД переходит из одного консистентного состояния в другое
  • Все правила целостности соблюдены

I — Isolation (Изоляция)

  • Параллельные транзакции не видят друг друга промежуточные состояния
  • Предотвращает race conditions

D — Durability (Долговечность)

  • Если транзакция успешна, данные постоянны (даже при сбое)

Простой пример: перевод денег

# БЕЗ транзакции (опасно!)
user1.balance -= 100  # Вычли деньги
# ... система упала, данные потеряны!
user2.balance += 100  # Так и не добавили

# С ТРАНЗАКЦИЕЙ (безопасно!)
try:
    user1.balance -= 100
    user2.balance += 100
    commit()  # Успех!
except Exception:
    rollback()  # Откатили оба изменения

SQL синтаксис

-- Явное управление транзакциями
BEGIN;  -- или START TRANSACTION
  UPDATE users SET balance = balance - 100 WHERE id = 1;
  UPDATE users SET balance = balance + 100 WHERE id = 2;
COMMIT;  -- Сохранить все изменения

-- Откат при ошибке
BEGIN;
  UPDATE accounts SET balance = balance - 50 WHERE id = 1;
  -- Ошибка!
ROLLBACK;  -- Вернулись к начальному состоянию

Django ORM

from django.db import transaction

# Простая транзакция
with transaction.atomic():
    user1 = User.objects.get(id=1)
    user2 = User.objects.get(id=2)
    user1.balance -= 100
    user2.balance += 100
    user1.save()
    user2.save()
    # При выходе из контекста — автоматический commit
    # При исключении — автоматический rollback

# Явное управление
from django.db import connection

cursor = connection.cursor()
try:
    cursor.execute("BEGIN")
    cursor.execute("UPDATE users SET balance = balance - 100 WHERE id = 1")
    cursor.execute("UPDATE users SET balance = balance + 100 WHERE id = 2")
    cursor.execute("COMMIT")
except Exception:
    cursor.execute("ROLLBACK")
    raise

SQLAlchemy

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

engine = create_engine('postgresql://...')
Session = sessionmaker(bind=engine)
session = Session()

try:
    user1 = session.query(User).get(1)
    user2 = session.query(User).get(2)
    user1.balance -= 100
    user2.balance += 100
    session.commit()  # Успешная транзакция
except Exception:
    session.rollback()  # Откат при ошибке
    raise
finally:
    session.close()

# Или более элегантно:
from contextlib import contextmanager

@contextmanager
def get_session():
    session = Session()
    try:
        yield session
        session.commit()
    except Exception:
        session.rollback()
        raise
    finally:
        session.close()

with get_session() as session:
    user = session.query(User).get(1)
    user.balance -= 100

Уровни изоляции (Isolation Levels)

По умолчанию разные БД используют разные уровни:

READ UNCOMMITTED (самый слабый)

  • Транзакция видит "грязные" данные (uncommitted changes)
  • Самый быстрый, но опасный

READ COMMITTED (по умолчанию в PostgreSQL)

  • Видит только подтверждённые данные
  • Может быть phantom read

REPEATABLE READ (по умолчанию в MySQL)

  • Одинаковые SELECT возвращают одинаковые данные в транзакции
  • Защита от non-repeatable read

SERIALIZABLE (самый строгий)

  • Полная изоляция, транзакции как будто идут друг за другом
  • Самый медленный
from django.db import transaction

# Установить уровень изоляции
with transaction.atomic():
    with transaction.set_autocommit(True):
        # Код здесь
        pass

# SQLAlchemy
from sqlalchemy.pool import StaticPool

engine.execute(
    "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE"
)

Проблемы при параллельных транзакциях

Dirty Read

# T1: читает uncommitted изменение от T2
T1: SELECT balance FROM users WHERE id = 1  # 1000
T2: UPDATE users SET balance = 500 WHERE id = 1
T1: SELECT balance FROM users WHERE id = 1  # 500 (грязное чтение!)
T2: ROLLBACK  # T2 откатилась, но T1 видит 500

Non-Repeatable Read

# T1: одно и то же SELECT возвращает разные результаты
T1: SELECT balance FROM users WHERE id = 1  # 1000
T2: UPDATE users SET balance = 500 WHERE id = 1
T2: COMMIT
T1: SELECT balance FROM users WHERE id = 1  # 500 (изменилось!)

Phantom Read

# T1: количество строк изменилось в одной транзакции
T1: SELECT COUNT(*) FROM orders WHERE status = 'pending'  # 5
T2: INSERT INTO orders (status) VALUES ('pending')
T2: COMMIT
T1: SELECT COUNT(*) FROM orders WHERE status = 'pending'  # 6 (phantom!)

Best Practices

# 1. Транзакции должны быть короткими
with transaction.atomic():
    # Быстрые БД операции
    user.balance -= 100
    user.save()
    # НЕ делай длительные операции здесь!

# 2. Не блокируй внешние ресурсы
with transaction.atomic():
    # Плохо
    response = requests.get('https://api.example.com')  # I/O блокирует!
    user.balance -= 100
    user.save()

# 3. Используй SELECT FOR UPDATE для критичных операций
with transaction.atomic():
    user = User.objects.select_for_update().get(id=1)
    # Теперь БД заблокирована для других транзакций
    user.balance -= 100
    user.save()

# 4. Обработай специфичные исключения
from django.db import IntegrityError

try:
    with transaction.atomic():
        User.objects.create(email=email)
except IntegrityError:
    # Email уже существует
    pass

Важные моменты

  • Транзакции необходимы для консистентности при множественных операциях
  • ACID гарантирует надёжность
  • Разные БД, разные реализации и уровни изоляции
  • Всегда используй контексты (with) для автоматического commit/rollback
  • Для критичных операций используй SELECT FOR UPDATE
  • Транзакции замедляют систему — держи их короткими

Транзакции — фундамент надёжной системы работы с БД.