JPA &Hibernate Flashcards
Что такое ORM? Что такое JPA? Что такое Hibernate и его основные интерфейсы? (6)
ORM (Object Relational Mapping) – это концепция преобразования данных из объектно-ориентированного языка в реляционные БД и наоборот.
JPA (Java Persistence API)– это стандартная для Java спецификация, описывающая принципы ORM. JPA не умеет работать с объектами, а только определяет правила, как должен действовать каждый провайдер (Hibernate, EclipseLink), реализующий стандарт JPA.
JPA определяет правила, по которым должны описываться метаданные отображения и как должны работать провайдеры. Каждый провайдер обязан реализовывать все из JPA, определяя стандартное получение, сохранение, управление объектами. Можно добавлять свои классы и интерфейсы.
Гибкость – код написанный с использование классов и интерфейсов JPA, позволяет гибко менять одного провайдера на другого, но если использовать классы, аннотации и интерфейсы из конкретного провайдера, то это работать не будет.
JDO входит в JPA, NoSQL.
Hibernate – библиотека, являющаяся реализацией JPA-спецификации, в которой можно использовать не только стандартные API-интерфейсы JPA, но и реализовать свои классы и интерфейсы.
Важные интерфейсы Hibernate:
Session extends EntityManager – обеспечивает физическое соединение между приложением и БД. Это единица работы Hibernate осуществляющая DML команды.
SessionFactory – это фабрика для объектов Session. Обычно её (потокобезопасный) синглтон создается во время запуска приложения и сохраняется для последующего использования. Является потокобезопасным объектом и используется всеми потоками приложения.
Transaction – однопоточный короткоживущий объект, используемый для атомарных операций. Это абстракция приложения от основных JDBC-транзакций. Сессия может включать несколько транзакций.
Query – интерфейс позволяет выполнять запросы к БД. Запросы написаны на HQL или на SQL.
Configuration - этот объект используется для создания объекта SessionFactory и конфигурирует сам Hibernate
Criteria - Используется для создания и выполнения объекто-ориентированных запроса на получение объектов.
https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/chapters/
Различия JPA и JDBC?
JDBC является более низкоуровневой (и более старой) спецификацией, чем JPA.
JDBC - это API-интерфейс для прямого взаимодействия с базой данных с использованием чистого SQL. При использовании JDBC вам необходимо преобразовать набор результатов в объекты Java.
JPA использует JDBC снизу и действует на высшем уровне абстракции осуществляя ORM.
SessionFactory vs EntityManagerFactory и Session vs EntityManager?
Hibernate появился раньше JPA. К этому времени у HIBERNATE был большой наработанный функционал, а для первой версии JPA удалось согласовать только часть этого объема функционала. Поэтому, разработчики HIBERNATE сознательно пошли на то, чтобы в HIBERNATE имелось два пути работы - старый путь - нативный HIBERNATE (через интерфейс Session) и новый путь JPA (через интерфейс EntityManager).
Интерфейсы разные, методы как правило имеют одинаковые названия. Различия есть и в других элементах. При этом, функциональность нативного HIBERNATE значительно больше, чем у JPA. И вообще, реализация EntityManager является оберткой (wrap) реализации Session. Класс SessionImpl реализует интерфейс Session, а Session расширяет интерфейс EntityManager.
Что такое Entity?
Entity – это легковесный хранимый объект бизнес логики.
Это класс, который можно смапить на табицу БД.
Что такое EntityManager? Какие функции он выполняет? (5)
EntityManager – интерфейс JPA, который описывает API для всех основных операций над Entity, а также для получения данных и других сущностей JPA.
Основные операции:
1. Операции над Entity: persist (добавление Entity), merge (обновление), remove (удаление), refresh (обновление данных), detach (удаление из управление JPA), lock (блокирование Entity от изменений в других thread).
2. Получение данных: find (поиск и получение Entity), createQuery, createNamedQuery, createNativeQuery, contains, createNamedStoredProcedureQuery, createStoredProcedureQuery.
3. Получение других сущностей JPA: getTransaction, getEntityManagerFactory,
getCriteriaBuilder, getMetamodel, getDelegate.
4. Работа с EntityGraph: createEntityGraph, getEntityGraph.
5. Общие операции над EntityManager или всеми Entities: close, clear, isOpen,
getProperties, setProperty.
Объекты EntityManager не являются потокобезопасными. Это означает, что каждый поток должен получить свой экземпляр EntityManager, поработать с ним и закрыть его в конце.
Каким условиям должен удовлетворять класс чтобы являться Entity? (9)
Требования к entity-классу :
1* должен быть помечен аннотацией Entity или описан в XML-файле;
2* должен содержать public или protected конструктор без аргументов (он также может иметь конструкторы с аргументами) – при получении данных из БД и формировании из них объекта сущности Hibernate должен создать этот объект сущности$
3* должен быть классом верхнего уровня (top-level class);
4* не может быть enum или интерфейсом;
5* не может быть финальным классом (final class);
6* не может содержать финальные поля или методы, если они участвуют в маппинге (persistent final methods or persistent final instance variables);
7* поля entity-класса должны быть напрямую доступны только методам самого entity- класса и не должны быть напрямую доступны другим классам, использующим этот entity. Такие классы должны обращаться только к методам (getter/setter методам или другим методам бизнес-логики в entity-классе);
8* должен содержать первичный ключ, то есть атрибут или группу атрибутов, которые уникально определяют запись этого entity-класса в базе данных.
9* если объект entity-класса будет передаваться по значению как отдельный объект (detached object), например, через удаленный интерфейс (through a remote interface), он должен реализовывать интерфейс Serializable;
Может ли абстрактный класс быть Entity?
Может, при этом он сохраняет все свойства Entity, за исключением того, что его нельзя непосредственно инициализировать.
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Employee {
@Id
@GeneratedValue
private long id;
private String name;
………….
}
@Entity
@Table(name = “FULL_TIME_EMP”)
public class FullTimeEmployee extends Employee {
private int salary;
………….
}
@Entity
@Table(name = “PART_TIME_EMP”)
public class PartTimeEmployee extends Employee {
private int hourlyRate;
………….
}
CREATE TABLE FULL_TIME_EMP (
id BIGINT NOT NULL,
name VARCHAR(255),
salary INTEGER NOT NULL,
CONSTRAINT pk_full_time_emp PRIMARY KEY (id));
CREATE TABLE PART_TIME_EMP ( id BIGINT NOT NULL, name VARCHAR(255), hourlyRate INTEGER NOT NULL, CONSTRAINT pk_full_time_emp PRIMARY KEY (id));
Может ли Entity класс наследоваться от не Entity классов (non-entity
classes)?
Может при помощи аннотации @MappedSuperclass
Может ли Entity класс наследоваться от других Entity классов?
Да
Может ли не Entity класс наследоваться от Entity класса?
Да, но это Bad Practice, так как сбивает столку пользователей кода.
Что такое встраиваемый (Embeddable) класс? Какие требования JPA
устанавливает к встраиваемым (Embeddable) классам?
Embeddable-класс – это класс, который не является entity сам по себе, а служит для того, чтобы выносить определение общих атрибутов для нескольких entity с целью переиспользования.
Например- Адрес.
Под него не создается таблица, а его поля включаются в таблицу содержащего его entity.
Чтобы избежать конфликтов мы можем кастомизировать названия колонок, созданных на основе этих полей:
~~~
@Embedded
@AttributeOverrides({
@AttributeOverride( name = “firstName”, column = @Column(name = “contact_first_name”)),
@AttributeOverride( name = “lastName”, column = @Column(name = “contact_last_name”)),
@AttributeOverride( name = “phone”, column = @Column(name = “contact_phone”))
})
private ContactPerson contactPerson;
~~~
Представляет собой реализацию принципа композиции в контексте ORM.
Во время выполнения каждый встраиваемый объкт принадлежит только одному объекту entity-класса и не может быть использован для передачи данных между объектами entity-классов (то есть такой класс не является общей структурой данных для разных объектов).
Такие классы должны удовлетворять тем же правилам, что entity-классы, за исключением того, что они не обязаны содержать первичный ключ и должны быть отмечены аннотацией @Embeddable, А поле этого класса в Entity аннотацией @Embedded.
Embeddable-класс может содержать другой встраиваемый класс.
Встраиваемый класс может содержать связи с другими Entity или коллекциями Entity, если такой класс не используется как первичный ключ или ключ map’ы.
https://www.baeldung.com/jpa-embedded-embeddable
Что такое Mapped Superclass?
Mapped Superclass это класс от которого наследуются Entity, он может содержать аннотации JPA, однако сам такой класс не является Entity а лишь включает свои поля в качестве колонок в таблицы классов-наследников.
Должен быть отмечен аннотацией @MappedSuperclass или соответственно описан в xml файле.
Для того, чтобы использовать Mapped Superclass, достаточно унаследовать его в классах-потомках
Mapped Superclass vs. Embeddable class
1) MappedSuperclass - наследование,
Embeddable class - композиция (экземпляр «части» может входить только в одно целое (или никуда не входить));
2) поля из Mapped Superclass могут быть у entity в одном экземпляре, полей из Embeddable class может быть сколько угодно (встроив в entity Embeddable class несколько раз и поменяв имена полей);
3) в entity нельзя создать поле с типом Mapped Superclass, а с Embeddable можно и нужно.
Какие три типа стратегии наследования мапинга (Inheritance Mapping
Strategies) описаны в JPA?
Inheritance Mapping Strategies описывает как JPA будет работать с классами-наследниками Entity:
-
Одна таблица на всю иерархию классов (SINGLE_TABLE) – все entity со всеми наследниками записываются в одну таблицу, для идентификации типа entity определяется специальная колонка «discriminator column».
Например, есть entity Animals c классами-потомками Cats и Dogs. При такой стратегии все entity записываются в таблицу Animals, но при этом имеют дополнительную колонку animalType, в которую соответственно пишется
значение «cat» или «dog». Минусом является то, что в общей таблице будут созданы все поля, уникальные для каждого из классов-потомков, которые будут пусты для всех других классов-потомков.
Например, в таблице animals окажется и скорость лазанья по дереву от
cats, и может ли пес приносить тапки от dogs, которые будут всегда иметь null для dog и cat соответственно.
Нельзя делать constraints notNull, но можно использовать триггеры.
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class MyProduct
-
Стратегия «соединения» (JOINED_TABLE) – каждый entity сохраняет в свою таблицу только первичный ключ и уникальные поля.
Все унаследованные колонки записываются в таблицу класса-предка.
ПК в наследнике является и ФК и ссылается на ПК в предке.
Чтобы задать кастомное имя для ПК/ФК используем:
@PrimaryKeyJoinColumn(name = “account_id”)
class DebitAccount extends Account
Минусы:
- потеря производительности от объединения таблиц (join) для любых операций.
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Animal
@Entity
@PrimaryKeyJoinColumn(name = “pet_id”)
class Pet extends Animal
- Таблица для каждого класса (TABLE_PER_CLASS) – суперкласс и каждый класс-наследник имеет свою таблицу в которой присутствуют в т.ч. унаследованные поля.
Минусы
- плохая поддержка полиморфизмаи
- для выборки всех классов иерархии потребуются большое количество отдельных sql-запросов или использование UNION-запроса.
- Не можем использвать стратегию генерации ключа “IDENTITY”
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Vehicle
Для задания стратегии наследования используется аннотация Inheritance (или соответствующие блоки).
https://www.baeldung.com/hibernate-inheritance
Как мапятся Enumы?
-
@Enumerated(EnumType.STRING) означает, что в базе будут храниться имена Enum.
Всё сломается при переименовании ЕНАМА -
@Enumerated(EnumType.ORDINAL) – в базе будут храниться порядковые номера Enum.
Всё сломается при добавленнии или изменении порядка значений. - Можно смапить enum в БД и обратно в методах с аннотациями **@PostLoad и @PrePersist. @EntityListener **над классом Entity, где указать класс, в котором создать два метода, помеченных этими аннотациями. Идея в том, чтобы в сущности иметь не только поле с Enum, но и вспомогательное поле.
Поле с Enum аннотируем @Transient, а в БД будет храниться значение из вспомогательного поля.
Нельзя иметь 2 енама с одинаковыми атрибутами. и использовать JPQL - В JPA с версии 2.1 можно использовать Converter для конвертации Enum’а в некое его значение для сохранения в БД и получения из БД. Нужно лишь создать новый класс, который реализует javax.persistence.AttributeConverter и переписать 2 метода
https://www.baeldung.com/jpa-persisting-enums-in-jpa
Как мапятся даты (до java 8 и после)?
Аннотация @Temporal до Java 8, в которой надо было указать, какой тип даты хотим использовать.
В Java 8 и далее аннотацию ставить не нужно.
Как “смапить” коллекцию примитивов?
@ElementCollection + @OrderBy / @OrderColumn
Если у сущности есть поле с коллекцией, то обычно ставят над ним аннотации @OneToMany либо @ManyToMany. Но данные аннотации применяются, когда это коллекция других сущностей (entities).
Если у сущности коллекция базовых или встраиваемых (embeddable) типов, то для этих случаев в JPA имеется специальная аннотация @ElementCollection, которая указывается в классе сущности над полем коллекции. Тогда все записи коллекции хранятся в отдельной таблице.
При добавлении новой строки в коллекцию она полностью очищается и заполняется заново, так как у элементов нет id. Можно решить с помощью @OrderColumn.
@CollectionTable позволяет редактировать таблицу с коллекцией.
Что такое владелец связи?
Речь идёт о владельце связи (у кого ФК)
Владеющая Сущность => Дочерняя Таблица
Владеемая сущность => Родительская таблица
В unidirectional есть только владеющая сущность.