ORM, JPA и Hibernate
JPA архитектура
Hibernate архитектура
Работа с Session
Entity
Persistence Context
Entity
Требования к Entity
ID
Embeddable
Наследование
MappedSuperclass
Single Table
Типы Ассоциаций
Полезные ссылки
Проблема equals/hashCode
Варианты решения
Проблема LazyInitializationException
Проблема N + 1
Варианты решения
Кэши
Кэши
2.92M
Category: programmingprogramming

Hibernate. Aston

1.

Hibernate
astondevs.ru

2.

ORM — технология программирования, которая связывает
базы данных с концепциями объектно-ориентированных
языков программирования, создавая «виртуальную
объектную базу данных». Если упростить, то ORM это связь
Java объектов и записей в БД:

3.

Плюсы:
1.
2.
3.
4.
5.
ORM упрощает жизнь разработчиков и уменьшает время написания кода.
При использовании ORM мы “говорим” с бд на объектном языке.
ORM среда не зависимая (можем менять СУБД как перчатки).
ORM реализует поддерживает ассоциации.
ORM поддерживает наследование, а также полиморфные запросы.
Минусы:
1.
2.
Страдает производительность.
Если реализуем нужны не простенькие CRUD операции, необходимо знать что происходит.

4. ORM, JPA и Hibernate

ORM — это по сути концепция о том, что Java объект можно
представить как данные в БД (и наоборот). Она нашла воплощение в
виде спецификации JPA — Java Persistence API.
JPA (Java Persistence API) это спецификация Java EE и Java SE,
описывающая систему управления сохранением java объектов в
таблицы реляционных баз данных в удобном виде
Hibernate - ORM фреймворк, который является реализацией
спецификации JPA

5. JPA архитектура

• EntityManagerFactory – создает и управляет EntityManager
• EntityManager – предоставляет API для persist’инга
сущностей (Entity)
• Entity – java объекты, которые мы храним в БД.
• EntityTransaction – позволяет управлять транзакциями,
связан 1 к 1 с EntityManager.
• Query – интефейс используемый для контроля выполнения
запросов.
• Persistence – позволяет получить доступ к
EntityManagerFactory (использовать его вам не нужно)

6. Hibernate архитектура

7.

8.

• Session можно рассматривать, как аналог Connection из JDBC, т.к. сессия является физическим
соединением с БД.
• Не является потокобезопасной.
• Является легковесным объектом, создается и удаляется по необходимости.
• Жизненный цикл по умолчанию привязан к транзакции.

9. Работа с Session

1. Session предоставляет API для работы с сущностями:
void persist(Object var1);
void delete(Object var1);
<T> T find(Class<T> entityClass, Object primaryKey);
2. JPQL/HQL - ООП’ный аналог sql. Сессия позволяет создавать Query и выполнять их.
3. Criteria API - это механизм, позволяющий динамически создавать запросы к бд, при помощи java кода.
Удобен в случае, если у нас есть большая вариативность потенциальных запросов, на пример если мы
можем отсортировать пользователей по n полям(имя/возраст итд) и в любой комбинации этих полей.

10. Entity

11. Persistence Context

Один или несколько EntityManager образуют или могут образовать persistence context. Наличие
persistence context означает, что для каждой существующей на данный момент сущности есть
EntityManager, который следит за её состоянием.
PC также называется кэш первого уровня.
PC отслеживает все изменения над управляемой сущностью.
Каждый раз когда мы взаимодействуем с Session (EM) мы на самом деле взаимодействуем с PC.
По умолчанию живет столько же, сколько и транзакция. Создается лениво, т.е. при вызове метода.

12.

С точки зрения JPA
каждая
управляемая EntityMana
ger’ом сущность имеет
строго определённое
состояние и строго
определённые правила
перехода из состояния в
состояние.

13. Entity

Entity - это объект, который представляет собой отображение таблицы в Java.
Может в себе содержать:
Value types: Существуют только в рамках Entity
○ базовые типы (строки, числа …)
○ Embeddable types (встроенные ссылочные типы)
○ Коллекции
Entity types (другие Entity)

14. Требования к Entity


должен быть аннотирован @Entity
наличие идентификатора @Id
public/protected конструктор без аргументов
top-level class (не вложенный)
не может быть Enum или Interface
не финальный класс
абстрактные классы могут быть
не может иметь final поля, если они участвуют в маппинге
геттеры и сеттеры, не могут быть final
Если сущность будет использоваться удаленно, в качестве
открепленной, должен implement Serializable

15.

Вопрос на 1 балл
Почему мы не должны использовать final классы в качестве Entity?

16.

Превращение Entity в final ограничивает способность
Hibernate использовать прокси, что, в свою очередь, не
позволяет Hibernate применять некоторые оптимизации
производительности. Без прокси ваше приложение
теряет ленивую загрузку, что снижает
производительность.

17. ID

ID могут быть:
● генерируемые
● составные
Стратегии генерации ID
● Auto – стратегия по умолчанию. Берется одна из следующих 3 стратегий основываясь на
возможностях СУБД.
Identity – мапит id к авто инкрементируемой колонке. На пример к AUTO_INCREMENT in
MySQL.
Sequence – Мы определяем последовательность для генерации. При этом мы сначала
запрашиваем у СУБД следующий id и потом вставляем сущность.
● Table – id в таблице инкрементируется, самый медленный вариант, почему – читайте тут:
https://vladmihalcea.com/why-you-should-never-use-the-table-identifier-generator-with-jpa-andhibernate/

18. Embeddable

- Встраиваемый тип.
- В мире java это отдельный объект
- В мире БД находится в той же таблицы, что и
сама сущность
- У такого типа нет id.
- Существует только в контексте сущности, т.е.
не может быть удален, запрошен и тд

19. Наследование

Реляционные БД не имеют прямого способа сохранения иерархии наследования классов.
Для решения этой проблемы спецификация JPA выделяет 4 стратегии:
1.
MappedSuperclass – the parent classes, can't be entities
2.
Single Table – The entities from different classes with a common ancestor are placed in a single table.
3.
Joined Table – Each class has its table, and querying a subclass entity requires joining the tables.
4.
Table per Class – All the properties of a class are in its table, so no join is required.
Каждая стратегия влечет за собой разную структуру хранения данных.

20. MappedSuperclass

Самое простое, что можно придумать, это
описать в базовом классе некоторые общие
свойства и их отображение в базу данных и
потом наследоваться от базового класса,
включая это определение.
Аннотация @MappedSuperclass позволяет
включать класс и его jpa аннотации в
производный класс, не делая базовый класс
сущностью (БД не знает о его сущеcтвовании).
Типичное использование в примере выше — абстрактный базовый класс, несущий в себе
суррогатный первичный ключ.
В базе данных всё будет выглядеть, как если бы поля базового класса были определены
непосредственно в производном классе.

21. Single Table

• Стратегия по умолчанию.
• Хранит все данные базового класса и всех его производных классов в одной таблице. В этой таблице будут созданные
столбцы для всех возможных полей всех производных классов и отдельный столбец, в котором будет хранится признак
класса, то есть метка, указывающая к какому конкретному классу относится эта строка.
• Базовый класс аннотируется аннотацией @Inheritance и, по желанию, @DiscriminatorColumn, в параметрах которой можно
задать наименование и тип столбца, в котором будут храниться признаки класса. К производным классам добавляется
аннотация @DiscriminatorValue, задающее значение признака класса.

22.

Single Table
+ Этот подход хорош тем, что позволяет сравнительно быстро загружать объекты (не нужен Join с другими таблицами) и, при
этом, обрабатывать общие поля внешними средствами, без знания о структуре классов.
- С другой стороны, теряется возможность указывать not null ограничения для столбцов (страдает консистентность).

23.

Single Table
В качестве альтернативы сурогатной дескриминатор колонки, можно использовать
@DiscriminatorFormula - Об этом читайте сами!

24.

Joined Table
Другая стратегия — создавать для каждого производного класса свою собственную таблицу, в
которой будут храниться его собственные поля. А поля базового класса — в собственной таблице
базового класса.
+ Этот подход решает проблемы предыдущего, с not null ограничениями
- Но за счёт выполнения сравнительно медленной операции join при чтении данных
производного класса из базы.
Чтобы использовать эту стратегию, необходимо аннотировать родителя:
Детей аннотировать не нужно.

25.

Joined Table
-> Доменная модель
Когда селектим
дочернюю сущность
происходит left join с
родительской по
общему id.

26.

TABLE_PER_CLASS
Каждый класс, и базовый и производные, получают по собственной таблице в которой есть все их
поля, а таблицы не связаны между собой.
Данная стратегия похожа на MappedSuperclass, только родитель так же является сущностью.
Чтобы использовать эту стратегию, необходимо аннотировать родителя:
Детей аннотировать не нужно.
С точки зрения бд никакого наследования нет, мы просто мапим сущность к таблице, при этом
остается возможность использовать полиморфные запросы.
Полиморфные запросы будут использовать UNION.

27.

Ассоциации
Ассоциации описывают, как сущности формируют отношения, основываясь на join семантике БД.
Ассоциации могут быть только между сущностями.
Ассоциации основываются на первичном и внешнем ключах. При этом ассоциация может строиться
либо на ссылке ВК-ПК у таргет объекта, либо на основе промежуточной таблицы.

28. Типы Ассоциаций

@OneToOne
@OneToMany
@ManyToOne
@ManyToMany
Однонаправленные
Двунаправленные
MappedBy | JoinColumn
CascadeType.ALL
CascadeType.PERSIST
CascadeType.MERGE
CascadeType.REMOVE
CascadeType.DETACH
CascadeType.REPLICATE
CascadeType.SAVE_UPDATE
CascadeType.LOCK

29. Полезные ссылки

Общее описание:
https://thorben-janssen.com/ultimate-guide-association-mappings-jpa-hibernate/
Серия статей the best way to map…:
https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/
https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/
https://vladmihalcea.com/the-best-way-to-use-the-manytomany-annotation-with-jpa-and-hibernate/

30. Проблема equals/hashCode

При написании сущностей, самый простой вариант определения equals/hashCode – на основе id.

31. Варианты решения

1.
Прежде чем класть сущность в коллекцию, переводить в состояние persist.
2.
Использовать @NaturalId при переопределении equals/hashCode.
3.
Генерировать идентификатор в java коде, при этом использовать его при реализации
equals()/hashCode(), а так же в качестве первичного ключа.

32. Проблема LazyInitializationException

Если мы обратимся к полям, которые подгружаются лениво при закрытом PersistenceContext, у нас
возникнет LIE.
Для понимания сути этой проблемы, вы должны четко представлять, что такое:
1.
PersistenceContext
2.
Проксирование в Hibernate
3.
Ленивая загрузка

33.

Вопрос на 0.5 балла
Когда закрывается PersistenceContext?

34.

Варианты решения
Плохие:
1. Открывать транзакцию уровнем выше.
2. Выставить свойство enable_lazy_load_no_trans в true. При активации этой проперти любой
доступ к не загруженным ленивым полям будет обернут в новую Session.
3. Использовать FetchType.EAGER.
Адекватные:
1. Использовать JOIN FETCH.
2. Использовать EntityGraph.
https://thorben-janssen.com/hibernate-tips-difference-join-left-join-fetch-join/
https://www.baeldung.com/jpa-entity-graph

35. Проблема N + 1

Возникает в случаях, когда ORM выполняет 1 запрос для извлечения родительской сущности и N
запросов для извлечения дочерних сущностей.
Если не указать стратегию явно, для
поля topic подразумевается стратегия fetch =
FetchType.EAGER. (Эта стратегия по умолчанию).
Это означает, что при выборе комментариев (select c from
Comment c) Hibernate будет заполнять значением
поле topic. Для этого он выполнит
дополнительный select для каждого комментария.
А значит, возникнет n+1 проблема.

36. Варианты решения

1.
Для решения проблемы из примера, можно использовать FetchType.LAZY, но на самом деле
это не решение проблемы, а ее избегание. Т.к. когда-нибудь нам может понадобиться топик в
комментарии
2.
Join Fetch
3.
Entity graph

37.

Темы для самоизучения
1.
@DynamicInsert(true)
2.
@DynamicUpdate(true)

38. Кэши


Кеш первого уровня (First-level cache);
Кеш второго уровня (Second-level cache);
Кеш запросов (Query cache);

39. Кэши

Стратегии кэширования:
READ_ONLY
NONSTRICT_READ_WRITE
READ_WRITE
TRANSACTIONAL
English     Русский Rules