Hibernate

Hibernate — ORM-провайдер для Java. Он реализует Jakarta Persistence (JPA), строит SQL по отображению классов на таблицы и синхронизирует состояние объектов с базой данных.

Главное различие:

  • JPA задаёт контракт: EntityManager, аннотации и правила жизненного цикла;
  • Hibernate реализует этот контракт и добавляет собственные возможности;
  • JDBC остаётся нижним уровнем, через который в итоге выполняется SQL.

См. JPA Hibernate ORM и JPA Hibernate и JDBC сравнение интерфейсов.

Что происходит при работе

  1. Приложение открывает транзакцию.
  2. EntityManager загружает сущность и помещает её в Persistence Context.
  3. Hibernate хранит снимок загруженного состояния.
  4. При flush сравнивает снимок с текущим объектом — это dirty checking.
  5. Формирует INSERT, UPDATE и DELETE, учитывая порядок зависимостей.
  6. JDBC-драйвер отправляет команды базе.

flush синхронизирует контекст с БД, но не обязательно фиксирует транзакцию. commit фиксирует её и перед этим обычно вызывает flush.

За что платим

  • скрытая генерация SQL усложняет оценку стоимости запроса;
  • ленивые связи требуют живого контекста;
  • каскады могут сохранить или удалить больше данных, чем ожидалось;
  • неудачный fetch join размножает строки;
  • пакетная обработка без flush и clear раздувает память;
  • массовый JPQL/SQL-апдейт обходит состояние уже загруженных сущностей.

Поэтому ORM не отменяет знание SQL, индексов и плана выполнения.

Практический минимум

  • включать SQL и статистику на диагностическом окружении;
  • явно выбирать границу транзакции;
  • по умолчанию загружать только нужные связи;
  • для списка проецировать данные в DTO, если сущность не нужна;
  • контролировать число запросов тестом или метрикой;
  • не использовать equals и hashCode, зависящие от изменяемых полей.

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

  1. Hibernate и JPA — одно и то же? Нет. JPA — спецификация, Hibernate — один из её провайдеров.
  2. Когда выполняется SQL? Не обязательно в момент вызова persist или изменения поля; обычно при flush, перед запросом либо при commit.
  3. Зачем нужен persistence context? Он гарантирует идентичность объекта в пределах контекста, отслеживает изменения и откладывает запись.
  4. Почему ORM создаёт N+1? Сначала загружается список сущностей, затем для каждой ленивой связи выполняется отдельный запрос.
  5. Можно ли полностью забыть JDBC? Нет: ограничения драйвера, транзакции, batch и фактический SQL остаются частью системы.

Связано: EntityManager, Жизненный цикл Entity в Hibernate, Fetch type Hibernate, Кэширование hibernate, Кейс N plus 1 при обходе иерархии.