Hibernate и JPA
JPA (Java Persistence API) – стандартная спецификация Java для ORM. Задает набор интерфейсов и аннотаций для управления постоянными данными (сущностями). Реализуется различными библиотеками, позволяя писать независимый от реализации код.
Hibernate – наиболее популярная реализация JPA. Это мощный ORM-фреймворк, который помимо базовой реализации спецификации предоставляет ряд расширений и дополнительных возможностей:
Маппинг и автоматизация: Генерация SQL, синхронизация объектов с БД, кэширование.
Ленивая загрузка (Lazy Loading): связанные объекты загружаются из БД по требованию, а не сразу, что экономит ресурсы (например, коллекция заказов у клиента не загружается до тех пор, пока к ней не обратятся).
Каскадные операции: автоматически распространяет действия на связанные сущности. Например, удаляя объект родителя, можно настроить каскадное удаление дочерних записей.
HQL (Hibernate Query Language): свой язык запросов, похожий на SQL, но оперирующий классами и свойствами, а не таблицами и колонками. Позволяет писать запросы, независимые от конкретной СУБД, используя имена сущностей.
Criteria API: объектно-ориентированный, типобезопасный способ составления запросов с помощью Java-кода (флюентный API). Удобен для динамически формируемых запросов, обеспечивает проверку на этапе компиляции (имен полей, типов).
Дополнительно: Hibernate поддерживает продвинутые возможности: кэш второго уровня (в памяти или распределенный кэш для уже загруженных данных между сессиями), аудирование изменений (Envers), валидацию данных через JSR 303 Bean Validation, и т.п.
Пояснение
JPA определяет, как мы описываем и управляем сущностями, а Hibernate – как именно это будет выполнено. Другие реализации JPA: EclipseLink (референсная реализация JPA, ранее TopLink), OpenJPA, etc., но Hibernate стал де-факто стандартом в индустрии.
Когда мы используем Hibernate через JPA, мы программируем в терминах интерфейсов JPA (EntityManager, EntityTransaction, Query и т.д.) и аннотаций JPA (@Entity, @Table...), а Hibernate выполняет "грязную работу". Код теоретически можно переключить на другую реализацию, заменив провайдер JPA, но на практике Hibernate специфичен (многие используют его расширения, напр. @Cascade, или пишут HQL, который равен JPQL по синтаксису, но всё же учитывают поведение Hibernate).
Lazy Loading: По умолчанию многие отношения в Hibernate ленивые. Это значит, когда вы загружаете сущность, связанные коллекции или объекты не подгружаются сразу. Вместо них находится прокси-объект. При попытке обратиться, например, к order.getItems(), если коллекция еще не загружена, Hibernate выполнит доп. SQL запрос чтобы ее заполнить. Это очень удобно для производительности – загружаются только необходимые данные – но требует внимательности: если вы закрыли сессию (EntityManager) и затем обращаетесь к ленивой коллекции, возникнет исключение LazyInitializationException. Поэтому либо продумывают границы сессии (например, в Spring транзакция держится открытой, пока данные нужны), либо используют JOIN FETCH в запросах, либо помечают как EAGER (но последний не всегда оптимален).
Каскад: Настраивается аннотацией cascade на отношениях @OneToMany, @OneToOne и др. Например, cascade = CascadeType.ALL на списке товаров у заказа означает, что при сохранении заказа Hibernate автоматически сохранит все новые товары в этом списке, а при удалении заказа – удалит связанные товары (если CascadeType.REMOVE включён). Без каскада такие связанные действия нужно делать вручную.
HQL и Criteria: О них подробнее далее, но важно понимать: JPA предлагает JPQL (Java Persistence Query Language) – язык запросов, описанный в спецификации. Hibernate поддерживает JPQL под своим именем HQL, расширяя его возможностями. Оба очень схожи (в простых случаях идентичны). Criteria API появился в JPA 2.0, а у Hibernate была своя реализация раньше; сейчас основной подход – использовать стандартный CriteriaBuilder и CriteriaQuery из JPA.
Использование Hibernate требует конфигурации: указания, где база, какие сущности маппить, и т.д. Раньше нужно было писать XML-файлы конфигураций (hibernate.cfg.xml) и маппинга (hbm.xml для каждой сущности). Сейчас практически все проекты переходят на аннотации и конфигурацию через свойства. Например, в Spring Boot достаточно указать в application.properties параметры: spring.jpa.hibernate.ddl-auto (стратегия генерации схемы), spring.jpa.show-sql (логирование SQL) и детали подключения (url, user, pass) – этого хватает, чтобы Hibernate настроился. При standalone использовании Hibernate можно создать Configuration програмmatically и добавить ему Properties. Тем не менее, знание старого способа (XML) полезно для поддержки legacy-кода, но в новых проектах упор делается на аннотации и авто-конфигурацию.
