middle
Что такое Dirty Checking и Flush?
Dirty Checking — механизм Hibernate, автоматически отслеживающий изменения Persistent-сущностей. При flush Hibernate сравнивает текущее состояние объекта с его снимком (snapshot), сделанным при загрузке, и генерирует UPDATE для изменённых полей.
Пример
@Transactional
public void updateUser(Long id) {
User user = entityManager.find(User.class, id); // загрузка + snapshot
user.setName("New Name"); // изменение в памяти
// НЕ нужен вызов save() или update()!
// При commit Hibernate обнаружит изменение и выполнит UPDATE
}
Flush
Flush — процесс синхронизации Persistence Context с базой данных. При flush все накопленные изменения (INSERT, UPDATE, DELETE) отправляются в БД.
Когда происходит flush:
- При
commit()транзакции (автоматически) - Перед выполнением JPQL/HQL-запроса (чтобы запрос видел актуальные данные)
- При явном вызове
entityManager.flush()
FlushMode
Пример
// AUTO (по умолчанию) — flush перед запросами и при commit
entityManager.setFlushMode(FlushModeType.AUTO);
// COMMIT — flush только при commit (не перед запросами)
entityManager.setFlushMode(FlushModeType.COMMIT);
Порядок операций при flush
- INSERT (новые сущности —
persist()) - UPDATE (изменённые сущности — Dirty Checking)
- DELETE коллекций
- INSERT/UPDATE коллекций
- DELETE (удалённые сущности —
remove())
Важное
- Dirty Checking автоматический — изменили поле Persistent-объекта → UPDATE при flush
- Flush =/= commit; flush отправляет SQL, commit фиксирует транзакцию
@DynamicUpdate— генерирует UPDATE только для изменённых столбцов (по умолчанию — все столбцы)@Transactional(readOnly = true)— подсказка Hibernate отключить Dirty Checking (оптимизация)
Частые ошибки
- Вызов
save()для уже managed-сущности — Spring Datasave()вызоветmerge(), создав лишнюю копию; для managed-сущностей достаточно изменить поля - Неожиданный UPDATE — изменили поле managed-объекта случайно → Hibernate выполнит UPDATE при flush
- Порядок flush — DELETE выполняется после INSERT/UPDATE; это может нарушить ограничения уникальности
- Flush в цикле —
entityManager.flush()в цикле может привести к деградации производительности
Как используется в 2026
- Dirty Checking — фундаментальный механизм, работает прозрачно
@DynamicUpdateрекомендуется для таблиц с большим количеством столбцовreadOnly = true— обязательный паттерн для read-only транзакций (экономит память и CPU)
На собеседовании: объясните, что не нужен явный save() для managed-сущностей — Hibernate сам обнаружит изменения через снимок (snapshot) при загрузке. Разделяйте flush и commit: flush отправляет SQL, commit фиксирует транзакцию. Упомяните
@DynamicUpdateиreadOnly = trueкак оптимизации.