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

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

1.7 Middle🔥 141 комментариев
#Python Core#Soft Skills

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

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

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

Атомарная транзакция в базах данных

Атомарная транзакция — это последовательность операций в базе данных, которые выполняются как одно неделимое целое: либо все выполнены успешно, либо ни одна. Это первый принцип ACID.

Концепция атомарности

Без атомарности (опасно):
├─ Деньги списаны со счёта Алисы         ✓
├─ ОШИБКА: система падает
└─ Деньги НЕ поступили Бобу              ✗
РЕЗУЛЬТАТ: деньги потеряны!

С атомарностью (безопасно):
├─ Деньги списаны со счёта Алисы
├─ Деньги поступили Бобу
├─ ОШИБКА: система падает
└─ Всё откатывается к начальному состоянию
РЕЗУЛЬТАТ: либо всё выполнено, либо ничего

Пример реального вреда

Сценарий: перевод денег между счётами

Счёт Алисы: 1000 руб
Счёт Боба: 500 руб

Алиса переводит 200 руб Бобу

БЕЗ атомарности (плохо)

def transfer_money(alice_id, bob_id, amount):
    # Шаг 1: списать со счёта Алисы
    alice = Account.objects.get(id=alice_id)
    alice.balance -= amount
    alice.save()  # Сохранено!
    
    # ОШИБКА здесь! Система падает
    raise Exception("Сетевая ошибка")
    
    # Шаг 2: добавить на счёт Боба (НИКОГДА не выполнится)
    bob = Account.objects.get(id=bob_id)
    bob.balance += amount
    bob.save()

РЕЗУЛЬТАТ:
Счёт Алисы: 800 руб  (деньги списаны!)
Счёт Боба: 500 руб   (деньги НЕ пришли!)
Деньги потеряны!

С атомарностью (хорошо)

from django.db import transaction

@transaction.atomic
def transfer_money(alice_id, bob_id, amount):
    # Шаг 1: списать со счёта Алисы
    alice = Account.objects.get(id=alice_id)
    alice.balance -= amount
    alice.save()
    
    # ОШИБКА здесь!
    raise Exception("Сетевая ошибка")
    
    # Шаг 2: добавить на счёт Боба
    bob = Account.objects.get(id=bob_id)
    bob.balance += amount
    bob.save()

РЕЗУЛЬТАТ:
Счёт Алисы: 1000 руб (ОТКАЧЕНО!)
Счёт Боба: 500 руб   (ОТКАЧЕНО!)
Всё остаётся как было - безопасно!

ACID в деталях

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

  • Либо все операции выполнены, либо ни одна
  • Нет промежуточных состояний

C — Consistency (Согласованность)

  • База остаётся в согласованном состоянии
  • Все ограничения (constraints) соблюдены

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

  • Одновременные транзакции не мешают друг другу
  • Каждая видит согласованное состояние

D — Durability (Надёжность)

  • Успешно выполненная транзакция сохранится
  • Даже при сбое системы

Использование транзакций в Django

Декоратор @transaction.atomic

from django.db import transaction

@transaction.atomic
def create_order(user, products):
    # Создать заказ
    order = Order.objects.create(user=user)
    
    # Добавить товары
    for product in products:
        OrderItem.objects.create(
            order=order,
            product=product,
            quantity=product.quantity
        )
    
    # Обновить количество на складе
    for product in products:
        product.stock -= product.quantity
        product.save()
    
    # Если всё выполнено — автоматически commit
    # Если ошибка — автоматически rollback
    return order

Context manager (with statement)

from django.db import transaction

def process_payment(order_id):
    with transaction.atomic():
        order = Order.objects.get(id=order_id)
        
        # Списать деньги
        payment = Payment.objects.create(
            order=order,
            amount=order.total_price,
            status='pending'
        )
        
        # Проверить баланс (может выбросить исключение)
        check_balance(order.user)
        
        # Отправить на процессинг
        payment.process()
        
        # Обновить статус заказа
        order.status = 'paid'
        order.save()
        
        # Всё успешно — commit
    # Если исключение — rollback и re-raise

Commit и Rollback

Commit — сохранить изменения

from django.db import connection

with connection.cursor() as cursor:
    cursor.execute("UPDATE accounts SET balance = balance - 200 WHERE id = 1")
    cursor.execute("UPDATE accounts SET balance = balance + 200 WHERE id = 2")
    # Автоматический commit в конце блока

Rollback — отменить изменения

from django.db import transaction

try:
    with transaction.atomic():
        # Операции
        update_inventory()
        process_payment()  # Может выбросить исключение
except PaymentFailed:
    # Автоматический rollback — inventory вернётся в прежнее состояние
    print("Платёж не пошёл, инвентарь откачен")

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

Разные БД поддерживают разные уровни:

Read Uncommitted — самый слабый

Транзакция 1: UPDATE balance = 500
Транзакция 2: READ balance = 500  (грязное чтение!)
Транзакция 1: ROLLBACK
Транзакция 2: видела 500, но было отачено!

Read Committed — стандартно

Транзакция 1: UPDATE balance = 500
Транзакция 2: READ balance = 300  (не видит незафиксированные)
Транзакция 1: COMMIT
Транзакция 2: READ balance = 500  (теперь видит)

Repeatable Read — лучше

Транзакция 1: READ balance = 300
Транзакция 2: UPDATE balance = 500, COMMIT
Транзакция 1: READ balance = 300  (одно и то же)

Serializable — самый строгий

База выполняет транзакции одну за другой
Медленнее, но максимально безопасно

В Django

from django.db import transaction

with transaction.atomic():
    # READ_COMMITTED (по умолчанию)
    # Может быть разное поведение в разных БД
    pass

Practical Pitfalls (частые ошибки)

Ошибка 1: N+1 queries внутри транзакции

# ПЛОХО
@transaction.atomic
def bad_order_processing():
    for product in products:  # Цикл
        product.refresh_from_db()  # N запросов!

# ХОРОШО
@transaction.atomic
def good_order_processing():
    products = Product.objects.all()  # 1 запрос
    for product in products:
        process(product)  # Уже в памяти

Ошибка 2: Deadlock (взаимная блокировка)

# Транзакция 1: блокирует A, ждёт B
# Транзакция 2: блокирует B, ждёт A
# → DEADLOCK!

# Решение: всегда блокируй в одинаковом порядке
with transaction.atomic():
    a = A.objects.select_for_update().get(id=1)
    b = B.objects.select_for_update().get(id=1)

Ошибка 3: Слишком длинная транзакция

# ПЛОХО
@transaction.atomic
def slow_import():
    for row in large_csv:
        # Долгая операция
        process_row(row)
        # Транзакция открыта весь час!

# ХОРОШО
def fast_import():
    for row in large_csv:
        with transaction.atomic():
            process_row(row)  # Каждая строка — отдельная транзакция

Raw SQL с транзакциями

from django.db import connection, transaction

def transfer_with_raw_sql(alice_id, bob_id, amount):
    with transaction.atomic():
        with connection.cursor() as cursor:
            cursor.execute(
                "UPDATE accounts SET balance = balance - %s WHERE id = %s",
                [amount, alice_id]
            )
            cursor.execute(
                "UPDATE accounts SET balance = balance + %s WHERE id = %s",
                [amount, bob_id]
            )
            # Commit при выходе из блока

Резюме

Атомарная транзакция — это гарантия целостности данных. Без неё денег можно терять, товары дублировать, и счёты не сходиться. Каждый Python разработчик должен понимать, как правильно использовать транзакции в своём коде.

Что такое атомарная транзакция? | PrepBro