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

В чем разница между commit и flush в SQLAlchemy?

2.0 Middle🔥 171 комментариев
#Базы данных (SQL)

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

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

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

Разница между commit и flush в SQLAlchemy

Это один из наиболее частых вопросов при работе с SQLAlchemy. Обе операции связаны с сохранением данных, но они выполняют разные задачи на разных уровнях абстракции.

Что такое flush?

Flush — это операция, при которой SQLAlchemy отправляет все накопленные изменения в память БД, но не подтверждает их окончательно. Это как сохранить документ в памяти ПК, но не записать на диск.

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import User

engine = create_engine("sqlite:///test.db")
Session = sessionmaker(bind=engine)
session = Session()

# Создаём нового пользователя
user = User(name="John", email="john@example.com")
session.add(user)

# Flush отправляет INSERT SQL в БД, но транзакция не завершена
session.flush()

# На этом моменте БД получила команду INSERT, но не подтвердила её
# Если произойдёт ошибка, данные не будут сохранены
print(f"User ID после flush: {user.id}")  # ID уже доступен!

# Если случится исключение до commit, ничего не сохранится
raise Exception("Ошибка!")

# Этот код никогда не выполнится
session.commit()

Что такое commit?

Commit — это операция, которая окончательно подтверждает все изменения в БД. Это как записать документ на диск. После commit все изменения становятся необратимыми (если не откатывать транзакцию явно).

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import User

engine = create_engine("sqlite:///test.db")
Session = sessionmaker(bind=engine)
session = Session()

# Создаём пользователя
user = User(name="Alice", email="alice@example.com")
session.add(user)

# Commit выполняет обе операции: flush + окончательное подтверждение
session.commit()

# Теперь данные гарантированно сохранены в БД
# Даже если程序 упадёт, данные останутся в БД
print(f"User успешно сохранён!")

Основные различия

Параметрflushcommit
УровеньУровень сессииУровень транзакции
Что делаетОтправляет SQL в БДПодтверждает все изменения
ОбратимостьМожно откатить (rollback)Нельзя откатить в БД (обратно только rollback)
Когда автоматически вызываетсяПеред query.all(), query.filter() и другими запросамиНикогда (явно вызываем)
Точка невозвратаНет — можно ещё откатитьДа — все изменения окончательны
ID объектаДоступен после flushДоступен после flush (commit только подтверждает)

Жизненный цикл операций

1. session.add(obj)          → Объект в памяти сессии
2. session.flush()           → SQL отправлен в БД (INSERT/UPDATE/DELETE)
3. session.commit()          → Транзакция подтверждена, изменения необратимы
4. session.rollback()        → Откатить всё (только если нет commit)

Практический пример с обработкой ошибок

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import User

engine = create_engine("sqlite:///test.db")
Session = sessionmaker(bind=engine)
session = Session()

try:
    # Добавляем пользователя
    user = User(name="Bob", email="bob@example.com")
    session.add(user)
    
    # Flush отправляет SQL
    session.flush()
    print(f"User ID после flush: {user.id}")  # ID уже есть
    
    # Имитируем ошибку
    if user.id == 1:
        raise ValueError("Некорректный ID")
    
    # Commit подтверждает
    session.commit()
    print("Данные сохранены")
    
except Exception as e:
    # Откатываем ВСЕ изменения (и flush, и всё остальное)
    session.rollback()
    print(f"Ошибка: {e}. Все изменения откачены")

Когда flush вызывается автоматически?

SQLAlchemy вызывает flush автоматически в следующих случаях:

session = Session()
user = User(name="Charlie")
session.add(user)

# Автоматический flush перед SELECT запросами
all_users = session.query(User).all()  # ← Flush вызывается здесь!

# Автоматический flush перед commit
session.commit()  # ← И здесь тоже

Важное замечание: expire_on_commit

session = Session()
user = User(name="Diana")
session.add(user)
session.commit()

# После commit, все атрибуты объекта становятся "истёкшими"
# Чтобы получить свежие данные, нужен новый запрос
print(user.name)  # Может быть None или старое значение

# Чтобы избежать этого:
session.refresh(user)  # Перезагрузить данные из БД
print(user.name)  # Теперь актуальное значение

Итоговый вывод

  • flush() — промежуточная операция, отправляет SQL в БД, но не подтверждает
  • commit() — окончательная операция, подтверждает все изменения и завершает транзакцию
  • flush() вызывается автоматически перед query и перед commit
  • Всегда используй try-except с rollback() для обработки ошибок
  • Commit — это точка, после которой откатить изменения в БД уже нельзя
В чем разница между commit и flush в SQLAlchemy? | PrepBro