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

Что такое Atomicity в ACID?

2.3 Middle🔥 121 комментариев
#Python Core

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

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

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

Atomicity в ACID: Атомарность транзакций

Atomicity (Атомарность) - это первый принцип ACID, который гарантирует, что транзакция либо полностью выполняется, либо полностью откатывается. Нет промежуточных состояний.

Суть Atomicity

Атомарность означает, что транзакция - это неделимая единица работы. Представь операцию как неделимый атом, который нельзя расщепить:

# Пример: перевод денег между счётами
# Транзакция: отправитель и получатель должны быть скоординированы

BEGIN TRANSACTION;

-- Шаг 1: снять со счёта отправителя
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;

-- Шаг 2: добавить на счёт получателя
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;

COMMIT;  -- Если оба UPDATE успешны
-- ИЛИ ROLLBACK, если что-то пошло не так

Если произойдёт сбой между шагом 1 и 2 (например, отключение электричества):

  • Если транзакция не коммитилась - оба изменения откатываются
  • Деньги не исчезнут и не появятся из ниоткуда
  • БД вернётся к исходному состоянию

Что может нарушить Atomicity

# ПЛОХО: без транзакции (нарушает Atomicity)
import sqlite3

conn = sqlite3.connect(':memory:')
cursor = conn.cursor()

# Без BEGIN TRANSACTION
cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1")
conn.commit()  # Коммитим первое изменение

# ОШИБКА ЗДЕСЬ!
cursor.execute("UPDATE accounts SET balance = balance + 100 WHERE id = 2")  # Может не выполниться
conn.commit()

# Результат: деньги исчезли со счёта 1, но не появились на счёте 2!

Правильная реализация Atomicity

import sqlite3

conn = sqlite3.connect(':memory:')
cursor = conn.cursor()

try:
    # BEGIN TRANSACTION (в SQLite автоматически)
    cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1")
    cursor.execute("UPDATE accounts SET balance = balance + 100 WHERE id = 2")
    
    # Если оба успешны - COMMIT
    conn.commit()
    print("Транзакция успешна")
    
except Exception as e:
    # Если ошибка - ROLLBACK (откат)
    conn.rollback()
    print(f"Ошибка: {e}. Все изменения откачены.")

SQLAlchemy и Atomicity

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, declarative_base
from sqlalchemy.exc import SQLAlchemyError

Base = declarative_base()
engine = create_engine('postgresql://user:password@localhost/db')
Session = sessionmaker(bind=engine)

class Account(Base):
    __tablename__ = 'accounts'
    id = Column(Integer, primary_key=True)
    balance = Column(Integer)

session = Session()

try:
    # Начало транзакции (автоматически при первом запросе)
    account1 = session.query(Account).filter_by(id=1).first()
    account2 = session.query(Account).filter_by(id=2).first()
    
    account1.balance -= 100
    account2.balance += 100
    
    # Commit - либо все изменения, либо ничего
    session.commit()
    print("Перевод успешен")
    
except SQLAlchemyError as e:
    # Rollback - откат всех изменений
    session.rollback()
    print(f"Ошибка при переводе: {e}")
finally:
    session.close()

Уровни изоляции и Atomicity

Атомарность работает на любом уровне изоляции (Isolation), но они взаимодействуют:

# PostgreSQL: установка уровня изоляции
conn.execute("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE")
conn.begin()

try:
    # Операции
    conn.commit()  # Атомарно
except:
    conn.rollback()  # Атомарный откат

Пример нарушения Atomicity (без обработки ошибок)

# Опасный код
def transfer_money_bad(account1_id, account2_id, amount):
    conn = sqlite3.connect(':memory:')
    cursor = conn.cursor()
    
    # Может упасть после первого UPDATE
    cursor.execute(f"UPDATE accounts SET balance = balance - {amount} WHERE id = {account1_id}")
    # Если здесь сбой, первое изменение зафиксировано!
    dangerous_operation()  # Ошибка!
    cursor.execute(f"UPDATE accounts SET balance = balance + {amount} WHERE id = {account2_id}")
    
    conn.commit()

# Правильный код
def transfer_money_good(account1_id, account2_id, amount):
    conn = sqlite3.connect(':memory:')
    cursor = conn.cursor()
    
    try:
        cursor.execute("BEGIN")
        cursor.execute(f"UPDATE accounts SET balance = balance - {amount} WHERE id = {account1_id}")
        dangerous_operation()  # Если ошибка - откат
        cursor.execute(f"UPDATE accounts SET balance = balance + {amount} WHERE id = {account2_id}")
        cursor.execute("COMMIT")  # Либо оба либо ничего
    except Exception as e:
        cursor.execute("ROLLBACK")
        raise

Context Manager для гарантии Atomicity

from contextlib import contextmanager

@contextmanager
def transaction(engine):
    conn = engine.connect()
    trans = conn.begin()
    try:
        yield conn
        trans.commit()  # Commit если нет ошибок
    except Exception:
        trans.rollback()  # Rollback если ошибка
        raise
    finally:
        conn.close()

# Использование
with transaction(engine) as conn:
    conn.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1")
    conn.execute("UPDATE accounts SET balance = balance + 100 WHERE id = 2")
    # Автоматический COMMIT в конце или ROLLBACK при ошибке

Ключевые моменты Atomicity

  1. "Всё или ничего" - транзакция либо полностью выполняется, либо полностью откатывается
  2. Защита от частичных обновлений - нет inconsistent состояний в БД
  3. Автоматический rollback при ошибках
  4. BEGIN / COMMIT / ROLLBACK - управление транзакциями
  5. Работает на уровне БД - гарантируется даже при сбоях приложения
  6. Context managers - удобный способ обеспечить Atomicity в Python

Реальный пример: онлайн платёж

# Без Atomicity: платеж висит в неопределённом состоянии
# С Atomicity: либо платеж полностью принят, либо полностью отклонен

def process_payment(user_id, amount):
    session = Session()
    try:
        # Транзакция начинается
        user = session.query(User).filter_by(id=user_id).with_for_update().first()
        
        if user.balance >= amount:
            user.balance -= amount
            session.add(Transaction(user_id=user_id, amount=amount, status='completed'))
            session.commit()  # Атомарный коммит
            return True
        else:
            session.rollback()
            return False
    except Exception as e:
        session.rollback()  # Откат при ошибке
        raise
    finally:
        session.close()

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

Что такое Atomicity в ACID? | PrepBro