Persistence Context

Persistence context — набор сущностей, которыми EntityManager управляет как одной единицей работы. В Hibernate ближайшее понятие — first-level cache внутри Session.

Три свойства, которые важно помнить

Идентичность

В одном контексте сочетанию «класс + первичный ключ» соответствует один managed-экземпляр:

User first = em.find(User.class, 42L);
User second = em.find(User.class, 42L);
assert first == second;

Это не означает, что повторный запрос никогда не уйдёт в БД: запрос может выполниться, но результат будет сведен к уже managed-объекту.

Dirty checking

Провайдер запоминает состояние при загрузке и перед flush обнаруживает изменения. Для managed-сущности не нужен отдельный update.

Write-behind

Команды на запись накапливаются до flush. Это позволяет упорядочивать SQL и собирать batch, но ошибка ограничения может проявиться позже строки кода, которая изменила объект.

Границы контекста

Обычно контекст живёт одну транзакцию. Паттерн Open Session in View продлевает его до конца HTTP-запроса и позволяет ленивую загрузку в контроллере или сериализаторе, но скрывает дополнительные запросы. Надёжнее загрузить нужные данные внутри сервисной транзакции.

При пакетной обработке:

for (int i = 0; i < items.size(); i++) {
    em.persist(items.get(i));
    if (i > 0 && i % 100 == 0) {
        em.flush();
        em.clear();
    }
}

Вопросы для повторения

  1. Первый уровень кэша можно отключить? Нет для managed-сущностей: это основа JPA-контекста.
  2. Почему контекст раздувает память? Он удерживает ссылки и снимки всех managed-сущностей.
  3. Что делает clear? Отсоединяет все сущности; после него dirty checking их не сохранит.
  4. Равен ли flush commit? Нет: flush отправляет SQL, а commit фиксирует транзакцию.
  5. Почему bulk update опасен? Он меняет строки напрямую, а уже загруженные объекты остаются устаревшими.

Связано: EntityManager, Жизненный цикл Entity в Hibernate, Кэширование hibernate.