← Назад к вопросам
В чем разница между 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 успешно сохранён!")
Основные различия
| Параметр | flush | commit |
|---|---|---|
| Уровень | Уровень сессии | Уровень транзакции |
| Что делает | Отправляет 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 — это точка, после которой откатить изменения в БД уже нельзя