Как управлять транзакциями в SQLAlchemy

Ответ

Транзакции в SQLAlchemy обеспечивают атомарность операций с базой данных (принцип ACID). Управлять ими можно несколькими способами, но предпочтительным является использование контекстных менеджеров.

1. Рекомендуемый способ: Контекстный менеджер Session.begin()

Это самый надежный и лаконичный подход. Он автоматически выполняет commit() при успешном выходе из блока или rollback() при возникновении исключения.

from sqlalchemy.orm import Session

# session создается ранее

with Session(engine) as session:
    try:
        with session.begin():
            # Все операции внутри этого блока — часть одной транзакции
            user = User(name='John Doe')
            session.add(user)
            # ... другие операции
        # Здесь транзакция автоматически закоммитится
    except Exception as e:
        # Здесь транзакция автоматически откатится
        print(f"Transaction failed: {e}")

2. Явное управление через Session

Классический подход, требующий ручного вызова commit() и rollback().

from sqlalchemy.orm import sessionmaker

Session = sessionmaker(bind=engine)
session = Session()

try:
    user = User(name='Jane Doe')
    session.add(user)
    session.commit() # Явный коммит
except:
    session.rollback() # Явный откат в случае ошибки
    raise
finally:
    session.close() # Важно закрывать сессию

3. Уровень Core: Контекстный менеджер Engine.begin()

Подходит для выполнения низкоуровневых SQL-запросов без использования ORM-сессий.

with engine.begin() as connection:
    connection.execute(text("UPDATE users SET active=true WHERE id=1"))
    # Автоматический commit или rollback

Ключевые принципы:

  • Атомарность: Всегда используйте транзакции для операций, которые должны быть выполнены как единое целое (например, перевод денег со счета на счет).
  • Безопасность: Контекстные менеджеры (with ...) — лучший способ избежать незакрытых сессий или незавершенных транзакций.
  • Вложенные транзакции: Для более сложных сценариев можно использовать session.begin_nested().