Комментарии (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
- "Всё или ничего" - транзакция либо полностью выполняется, либо полностью откатывается
- Защита от частичных обновлений - нет inconsistent состояний в БД
- Автоматический rollback при ошибках
- BEGIN / COMMIT / ROLLBACK - управление транзакциями
- Работает на уровне БД - гарантируется даже при сбоях приложения
- 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()
Атомарность - это фундамент надёжных приложений, особенно при работе с финансовыми данными, состояниями заказов и другой критичной информацией.