JPA &Hibernate Flashcards

1
Q

Что такое ORM? Что такое JPA? Что такое Hibernate и его основные интерфейсы? (6)

A

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/

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Различия JPA и JDBC?

A

JDBC является более низкоуровневой (и более старой) спецификацией, чем JPA.
JDBC - это API-интерфейс для прямого взаимодействия с базой данных с использованием чистого SQL. При использовании JDBC вам необходимо преобразовать набор результатов в объекты Java.

JPA использует JDBC снизу и действует на высшем уровне абстракции осуществляя ORM.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

SessionFactory vs EntityManagerFactory и Session vs EntityManager?

A

Hibernate появился раньше JPA. К этому времени у HIBERNATE был большой наработанный функционал, а для первой версии JPA удалось согласовать только часть этого объема функционала. Поэтому, разработчики HIBERNATE сознательно пошли на то, чтобы в HIBERNATE имелось два пути работы - старый путь - нативный HIBERNATE (через интерфейс Session) и новый путь JPA (через интерфейс EntityManager).

Интерфейсы разные, методы как правило имеют одинаковые названия. Различия есть и в других элементах. При этом, функциональность нативного HIBERNATE значительно больше, чем у JPA. И вообще, реализация EntityManager является оберткой (wrap) реализации Session. Класс SessionImpl реализует интерфейс Session, а Session расширяет интерфейс EntityManager.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Что такое Entity?

A

Entity – это легковесный хранимый объект бизнес логики.
Это класс, который можно смапить на табицу БД.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Что такое EntityManager? Какие функции он выполняет? (5)

A

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, поработать с ним и закрыть его в конце.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Каким условиям должен удовлетворять класс чтобы являться Entity? (9)

A

Требования к 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;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Может ли абстрактный класс быть Entity?

A

Может, при этом он сохраняет все свойства 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));
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Может ли Entity класс наследоваться от не Entity классов (non-entity
classes)?

A

Может при помощи аннотации @MappedSuperclass

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Может ли Entity класс наследоваться от других Entity классов?

A

Да

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Может ли не Entity класс наследоваться от Entity класса?

A

Да, но это Bad Practice, так как сбивает столку пользователей кода.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Что такое встраиваемый (Embeddable) класс? Какие требования JPA
устанавливает к встраиваемым (Embeddable) классам?

A

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Что такое Mapped Superclass?

A

Mapped Superclass это класс от которого наследуются Entity, он может содержать аннотации JPA, однако сам такой класс не является Entity а лишь включает свои поля в качестве колонок в таблицы классов-наследников.
Должен быть отмечен аннотацией @MappedSuperclass или соответственно описан в xml файле.

Для того, чтобы использовать Mapped Superclass, достаточно унаследовать его в классах-потомках

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Mapped Superclass vs. Embeddable class

A

1) MappedSuperclass - наследование,
Embeddable class - композиция (экземпляр «части» может входить только в одно целое (или никуда не входить));
2) поля из Mapped Superclass могут быть у entity в одном экземпляре, полей из Embeddable class может быть сколько угодно (встроив в entity Embeddable class несколько раз и поменяв имена полей);
3) в entity нельзя создать поле с типом Mapped Superclass, а с Embeddable можно и нужно.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Какие три типа стратегии наследования мапинга (Inheritance Mapping
Strategies) описаны в JPA?

A

Inheritance Mapping Strategies описывает как JPA будет работать с классами-наследниками Entity:

  1. Одна таблица на всю иерархию классов (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

  1. Стратегия «соединения» (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

  1. Таблица для каждого класса (TABLE_PER_CLASS) – суперкласс и каждый класс-наследник имеет свою таблицу в которой присутствуют в т.ч. унаследованные поля.

Минусы
- плохая поддержка полиморфизмаи
- для выборки всех классов иерархии потребуются большое количество отдельных sql-запросов или использование UNION-запроса.
- Не можем использвать стратегию генерации ключа “IDENTITY”

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Vehicle

Для задания стратегии наследования используется аннотация Inheritance (или соответствующие блоки).

https://www.baeldung.com/hibernate-inheritance

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Как мапятся Enumы?

A
  • @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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Как мапятся даты (до java 8 и после)?

A

Аннотация @Temporal до Java 8, в которой надо было указать, какой тип даты хотим использовать.
В Java 8 и далее аннотацию ставить не нужно.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Как “смапить” коллекцию примитивов?

A

@ElementCollection + @OrderBy / @OrderColumn
Если у сущности есть поле с коллекцией, то обычно ставят над ним аннотации @OneToMany либо @ManyToMany. Но данные аннотации применяются, когда это коллекция других сущностей (entities).

Если у сущности коллекция базовых или встраиваемых (embeddable) типов, то для этих случаев в JPA имеется специальная аннотация @ElementCollection, которая указывается в классе сущности над полем коллекции. Тогда все записи коллекции хранятся в отдельной таблице.
При добавлении новой строки в коллекцию она полностью очищается и заполняется заново, так как у элементов нет id. Можно решить с помощью @OrderColumn.
@CollectionTable позволяет редактировать таблицу с коллекцией.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

Что такое владелец связи?

A

Речь идёт о владельце связи (у кого ФК)
Владеющая Сущность => Дочерняя Таблица
Владеемая сущность => Родительская таблица

В unidirectional есть только владеющая сущность.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

Какие есть виды связей?

A

1. OneToOne – когда один экземпляр Entity может быть связан не больше чем с одним экземпляром другого Entity.
2 варианта:
- в дочерней таблице ПК = ФК:
в классе Child аннотируем поле Parent @OneToOne & @PrimaryKeyJoinColumn, И переопределяем setParent(Parent p) {
p.setChild(this);
this.p = p;
this.id = p.gerId();
}
а в сущности Parent делаем @OneToOne (mappedBy = “названия поля этой сущности в “дочернем” классе, cascade..).

- В дочерней таблице свой ПК (IDENTITY) и ФК (not null, unique):
в Child вешаем @JoinColumn( аналог REFERENCES в sql: в атрибуте name объяснить, на какую колонку ссылаться в родительской таблице) - это необязательно, если ПК в Parent - “parent_id” И переопределяем setParent(Parent p) {
p.setChild(this);
this.p = p;
}
а в сущности Parent делаем @OneToOne (mappedBy = “имя поля Parent в Child классе”, cascade..).

2. OneToMany – когда один экземпляр Entity может быть связан с несколькими экземплярами других Entity.
Храним коллекцию.
~~~
public class Cart {
@OneToMany(mappedBy=”cart”)
private Set<Item> items;
mappedBy="name of the Cart field in the Item class"
~~~
Для корректной работы с Set надо исклчить items из equals&hashcode&tostring</Item>

3. ManyToOne – обратная связь для OneToMany. Несколько экземпляров Entity могут быть связаны с одним экземпляром другого Entity.

public class Item {
    
    @ManyToOne(optional = false)
    @JoinColumn(name="cart_id", nullable=false)
    private Cart cart;
optional false = делает эту колонку NOT NULL и следовательно при запросе выполнится Inner Join
 nullable false - if cart = null => ошибка
                           if cart_id = null => сработает
}

4. ManyToMany – экземпляры Entity могут быть связаны с несколькими экземплярами друг друга. Каждый из двух Entity может иметь по несколько других Entity.

Каждую группу можно дополнительно разделить на
1. Bidirectional с использованием mappedBy * на стороне, где указывается @OneToMany
2. Unidirectional- с использованием (или без) @JoinColumn(name = (cart_id)) на стороне, где указывается @OneToMany, тогда создается таблица, содержащая 2 колонки с айдишниками

    • без использования mappedBy хибер создаёт смежную таблицу, в которой связывает значениях таблиц. Что ухудшает производительность.
20
Q

Что такое каскады?

A

Каскадирование – это когда действие с целевой Entity будет применено к связанной Entity.

JPA CascadeType:
* ALL гарантирует, что все персистентные события, которые происходят на родительском объекте, будут переданы дочернему объекту;
* PERSIST означает, что операции save() или persist() каскадно передаются связанным объектам;
* MERGE означает, что связанные entity объединяются, когда объединяется entity-владелец;
* REMOVE удаляет все entity, связанные с удаляемой entity;
* DETACH отключает все связанные entity, если происходит «ручное отключение»;
* REFRESH повторно считывает значение данного экземпляра и связанных сущностей из базы данных при вызове refresh().

21
Q

OrphanRemoval vs cascadeType.remove

A

@OrphanRemoval - управляет поведением осиротевшими сущностями. OrphanRemoval объявляет, что при удалении экземпляра из коллекции, его надо удалить и из базы.

CascadeType.REMOVE: «Дочерняя» сущность удаляется только тогда, когда ее «Родитель» удаляется.

Если указан orphanRemoval = true, удаленный экземпляр адреса автоматически удаляется. Если указан только cascade = CascadeType.REMOVE автоматическое действие не выполняется, поскольку удаление отношения не является удалить операцию.

22
Q

Разница между PERSIST и MERGE?

A

persist(entity) следует использовать с новыми объектами, чтобы добавить их в БД (если объект уже существует в БД, будет выброшено исключение EntityExistsException)

Если использовать merge(entity), то сущность, которая уже управляется в контексте персистентности, будет заменена новой сущностью (обновленной), и копия этой обновленной сущности вернется обратно. Рекомендуется использовать для уже сохраненных сущностей.

23
Q

Какие два типа fetch стратегии в JPA вы знаете?

A

LAZY — шаблон проектирования, согласно которому данные поля сущности будут загружены только во время первого обращения к этому полю.
EAGER — шаблон проектирования, согласно которому данные поля будут загружены немедленно вместе с сущностью, то есть мы должны проинициализировать все ассоциации

** @ManyToOne(fetch = FetchType.LAZY)**
@JoinColumn(name = “user_id”, nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
@JsonBackReference
@NotNull(groups = View.Persist.class)
private User user;

	https://www.baeldung.com/hibernate-lazy-eager-loading
24
Q

Какие четыре статуса жизненного цикла Entity объекта (Entity Instance’s Life
Cycle) вы можете перечислить?

A

У Entity объекта существует четыре статуса жизненного цикла:

new (Transient) — объект создан, но при этом ещё не имеет сгенерированных первичных ключей и пока ещё не сохранен в базе данных, не привязан к текущему контексту персистентности (к сессии и к кэшу первого уровня). NB: NB: если генерация id для сущности производится базой данных - объекты в состоянии Transient не должны содержать никиаких значений в поле id

managed (Persistent) — объект создан и управляется JPA, хранится в persistent context и имеет сгенерированные первичные ключи.
В это состояние может попасть объект из абсолютно любого состояния:
- из состояния Transient - методом persist().
- из состояния Detached - метод merge()
- если ассоциированная с объектом запись была удалена, и объект находится в состоянии Removed - методом persist(), чтобы снова сохранить данные в базу, а объект перевести в состояния Persistent.

detached — объект был создан, но не управляется (или больше не управляется) JPA.
Объект, который до этого был привязан к контексту персистентности, но теперь отделен от него. Отделение могло произойти по двум причинам:
- контекст персистентности был закрыт (закончилась тарзакция, закрылась сессия),
- объект был явно отделен методом detach или clear от ещё существующего контекста.
Подобный объект имеет заполненное поле id, сгенерированное базой, но контекст персистентности больше не следит за изменением этого объекта.

removed — объект создан, управляется JPA, но будет удален после commit’a транзакции.
Объект, ассоциированная с которым запись была удалена из базы. Такой объект так же не отслеживается контекстом персистентности и информация о нем больше не хранится в кэше первого уровня.

25
Q

Как влияет операция persist на Entity объекты каждого из четырех статусов?

A

new → managed, объект будет сохранен в базу при commit-е транзакции или в результате flush-операций;
* managed → операция игнорируется, однако зависимые Entity могут поменять статус на managed, если у них есть аннотации каскадных изменений;
* detached → exception сразу или на этапе commit-а транзакции;
* removed → managed, но только в рамках одной транзакции.

26
Q

Как влияет операция remove на Entity объекты каждого из четырех статусов?

A
  • new → операция игнорируется, однако зависимые Entity могут поменять статус на removed, если у них есть аннотации каскадных изменений и они имели статус managed;
  • managed → removed, запись объекта в базе данных будет удалена при commit-е транзакции (также произойдут операции remove для всех каскаднозависимых объектов);
  • detached → exception сразу или на этапе commit-а транзакции;
  • removed → операция игнорируется.
27
Q

Как влияет операция merge на Entity объекты каждого из четырех статусов?

A
  • new → будет создан новый managed entity, в который будут скопированы данные прошлого объекта;
    * managed → операция игнорируется, однако операция merge сработает на
    каскаднозависимые Entity, если их статус не managed;
  • detached → либо данные будут скопированы в существующий managed entity с тем же первичным ключом, либо создан новый managed, в который скопируются данные;
  • removed → exception сразу или на этапе commit-а транзакции.
28
Q

Как влияет операция refresh на Entity объекты каждого из четырех статусов?

A
  • managed → будут восстановлены все изменения из базы данных данного Entity, также произойдет refresh всех каскаднозависимых объектов;
  • new, removed, detached → exception.
29
Q

Как влияет операция detach на Entity объекты каждого из четырех статусов?

A
  • managed, removed → detached;
  • new, detached → операция игнорируется.
30
Q

Для чего нужна аннотация Basic?

A

@Basic указывает на простейший тип маппинга данных на колонку таблицы базы данных. Может быть применена к полю любого из следующих типов:
* примитивы и их обертки;
* java.lang.String;
* java.math.BigInteger;
* java.math.BigDecimal;
* java.util.Date;
* java.util.Calendar;
* java.sql.Date;
* java.sql.Time;
* java.sql.Timestamp;
* byte[] or Byte[];
* char[] or Character[];
* enums;
* любые другие типы, которые реализуют Serializable.

Аннотация @Basic определяет 2 атрибута:
1. optional – boolean (по умолчанию true) – определяет, может ли значение поля или свойства быть null. Игнорируется для примитивных типов. Но если тип поля не примитивного типа, то при попытке сохранения сущности будет выброшено исключение.
2. fetch – FetchType (по умолчанию EAGER) – определяет, должен ли этот атрибут извлекаться незамедлительно (EAGER) или лениво (LAZY). Это необязательное требование JPA, и провайдерам разрешено незамедлительно загружать данные, даже для которых установлена ленивая загрузка.

Аннотацию @Basic можно не ставить, как это и происходит по умолчанию.
Без аннотации @Basic при получении сущности из БД по умолчанию ее поля базового типа загружаются принудительно (EAGER) и значения этих полей могут быть null.

В целом @Basic надо использовать, если мы хотим изменить дефолтное поведение optional & fetch атрибутов

https://www.baeldung.com/jpa-basic-annotation

31
Q

Для чего нужна аннотация Column?

A

Cопоставляет поле класса столбцу таблицы, а её атрибуты определяют поведение в этом столбце, используется для генерации схемы базы данных.

@Basic vs @Column:
Коротко, в @Column задаем имя и constraints, а в @Basic – FetchTypes.

Атрибуты @Basic применяются к сущностям JPA, тогда как атрибуты @Column применяются к столбцам базы данных.
@Basic имеет атрибут optional, который говорит о том, может ли поле объекта быть null или нет; с другой стороны атрибут nullable аннотации @Column указывает, может ли соответствующий столбец в таблице быть null.
Мы можем использовать @Basic, чтобы указать, что поле должно быть загружено лениво.
Аннотация @Column позволяет нам указать имя столбца в таблице и ряд других свойств: a. insertable/updatable - можно ли добавлять/изменять данные в колонке, по умолчанию true; b. length - длина, для строковых типов данных, по умолчанию 255.

32
Q

Для чего нужна аннотация Access?

A

Она определяет как JPA будет обращаться к атрибутам entity: как к полям класса (FIELD) или как к свойствам класса (PROPERTY), имеющие гетеры (getter) и сетеры (setter).

Совокупность полей и методов (свойств) сущности называется атрибутами.

Использовать ее стоит для переопределения дефолтного поведения Hibernate

Для чтения и записи полей Hibernate использует два подхода:

Field access (доступ по полям).
Hibernate напрямую работает с полями сущности, читая и записывая их.

Property access (доступ по свойствам).
Hibernate использует геттеры и сеттеры для чтения и записи полей сущности. Но есть требование - у сущности с property access названия методов должны соответствовать требованиям JavaBeans. Например, если у сущности Customer есть поле с именем firstName, то у этой сущности должны быть определены методы getFirstName и setFirstName для чтения и записи поля firstName.

При неявном определении типа доступа JPA требует, чтобы у всех сущностей в иерархии был единый тип доступа.

По умолчанию тип доступа определяется местом, в котором находится аннотация @Id. Если она будет над полем - это будет AccessType.FIELD, если над геттером - это AccessType.PROPERTY.

Чтобы явно определить тип доступа у сущности, нужно использовать аннотацию @Access, которая может быть указана у сущности, Mapped Superclass и Embeddable class, а также над полями или методами.

Аннотация @Access позволяет в иерархии сущностей с одним единым типом доступа безболезненно определить для одной или нескольких сущностей другой тип доступа. То есть в иерархии, где у всех тип доступа, например, field access, можно у какой-нибудь сущности указать тип доступа property access и это не нарушит работу Hibernate.

Если у сущности объявлена аннотация @Access(AccessType.FIELD):

  • значит аннотации маппинга нужно размещать над полями;
  • есть возможность у любых атрибутов сущности поменять тип доступа на property access, разместив аннотацию @Access(AccessType.PROPERTY) над соответствующими геттерами;
  • разместив аннотации маппинга над геттерами, не имеющими @Access(AccessType.PROPERTY), получим неопределенное поведение.

Если у сущности объявлена аннотация @Access(AccessType.PROPERTY):

  • значит аннотации маппинга нужно размещать над геттерами;
  • есть возможность у любых атрибутов сущности поменять тип доступа на field access, разместив аннотацию @Access(AccessType.FIELD) над соответствующими полями;
  • разместив аннотации маппинга над полями, не имеющими @Access(AccessType.FIELD), получим неопределенное поведение.

Поля, унаследованные от суперкласса, имеют тип доступа этого суперкласса.

Когда у одной сущности определены разные типы доступа, нужно использовать аннотацию @Transient для избежания дублирования маппинга.

https://thorben-janssen.com/access-strategies-in-jpa-and-hibernate/

33
Q

Для чего нужна аннотация Cacheable?

A

Аннотация @Cacheable размещается над классом сущности. Её действие распространяется на эту сущность и её наследников, если они не определили другое поведение.

Используется для указания того, должна ли сущность храниться в кэше второго уровня, в случае, если в файле persistence.xml (или в свойстве javax.persistence.sharedCache.mode конфигурационного файла) для элемента shared-cache-mode установлено одно из значений:

ENABLE_SELECTIVE: только сущности с аннотацией @Cacheable (равносильно значению по умолчанию @Cacheable(value=true)) будут сохраняться в кэше второго уровня.
DISABLE_SELECTIVE: все сущности будут сохраняться в кэше второго уровня, за исключением сущностей, помеченных аннотацией @Cacheable(value=false)как некэшируемые.
ALL: сущности всегда кэшируются, даже если они помечены как некэшируемые.
NONE: ни одна сущность не кэшируется, даже если помечена как кэшируемая. При данной опции имеет смысл вообще отключить кэш второго уровня.
UNSPECIFIED: применяются значения по умолчанию для кэша второго уровня, определенные Hibernate. Это эквивалентно тому, что вообще не используется shared-cache-mode, так как Hibernate не включает кэш второго уровня, если используется режим UNSPECIFIED.

34
Q

Для чего нужны аннотации @Embedded и @Embeddable?

A

@Embeddable – аннотация JPA, размещается над классом для указания того, что класс является встраиваемым в другие классы.
@Embedded – аннотация JPA, используется для размещения над полем в классе-сущности для указания того, что внедряется встраиваемый класс.

35
Q

Как смапить составной ключ?

A

1) Первый метод использования составного ключа включает класс ключа целиком в класс сущности: @EmbeddedId указывает на поле составного первичного ключа, а @Embeddable объявляет класс составным ключом.

2)
@IdClass
class AccountId{
private String accountNumber;
private String accountType;
}
@Entity
@IdClass(AccountId.class)
public class Account {
@Id
private String accountNumber;

@Id
private String accountType;
// other fields, getters and setters
}

36
Q

Для чего нужна аннотация ID? Какие @GeneratedValue вы знаете?

A

Определяет простой (не составной) первичный ключ, состоящий из одного
поля. В соответствии с JPA, допустимые типы атрибутов для первичного ключа:
* примитивные типы и их обертки;
* строки;
* BigDecimal и BigInteger;
* java.util.Date и java.sql.Date.

Если хотим, чтобы значение первичного ключа генерировалось автоматически, необходимо добавить первичному ключу аннотацию @GeneratedValue.
Возможны 4 варианта:
1. AUTO (default). Указывает, что Hibernate должен выбрать подходящую стратегию для конкретной базы данных, учитывая ее диалект, так как у разных БД разные способы по умолчанию. Поведение по умолчанию – исходить из типа поля идентификатора.
2. IDENTITY. Для генерации значения первичного ключа будет использоваться столбец IDENTITY, имеющийся в базе данных. Значения в столбце автоматически увеличиваются вне текущей выполняемой транзакции(на стороне базы, так что этого столбца не увидим, что
позволяет базе данных генерировать новое значение при каждой операции вставки.
В промежутках транзакций сущность будет сохранена.
3. SEQUENCE. Тип генерации, рекомендуемый документацией Hibernate. Для получения значений первичного ключа Hibernate должен использовать имеющиеся в базе данных механизмы генерации последовательных значений (Sequence). В БД можно будет увидеть
дополнительную таблицу. Но если БД не поддерживает тип SEQUENCE, то Hibernate автоматически переключится на тип TABLE. В промежутках транзакций сущность не будет сохранена, так как Hibernate возьмет из таблицы id hibernate-sequence и вернется обратно в приложение. SEQUENCE – это объект базы данных, который генерирует инкрементные
целые числа при каждом последующем запросе.
4. TABLE. Hibernate должен получать первичные ключи для сущностей из создаваемой для этих целей таблицы, способной содержать именованные сегменты значений для любого количества сущностей. Требует использования пессимистических блокировок, которые помещают все транзакции в последовательный порядок и замедляет работу приложения.

https://habr.com/ru/company/haulmont/blog/653843/

37
Q

Расскажите про аннотации @JoinColumn и @JoinTable? Где и для чего они
используются?

A

@JoinColumn используется для указания столбца FOREIGN KEY, используемого при установлении связей между сущностями.
Можно указать @JoinColumn как во владеющей таблице, так и во владеемой, но столбец с внешними ключами все равно появится во владеющей таблице.

Особенности использования:
* @OneToOne: означает, что появится столбец в таблице сущности-владельца связи, который будет содержать внешний ключ, ссылающийся на первичный ключ владеемой сущности;
* @OneToMany/@ManyToOne: если не указать на владеемой стороне связи @mappedBy, создается joinTable с ключами обеих таблиц. Но при этом же у владельца создается столбец с внешними ключами.

@JoinColumns используется для группировки нескольких аннотаций @JoinColumn, которые используются при установлении связей между сущностями или коллекциями, у которых составной первичный ключ и требуется несколько колонок для указания внешнего ключа.
В каждой аннотации @JoinColumn должны быть указаны элементы name и
referencedColumnName.

@JoinTable используется для указания связывающей (сводной, третьей) таблицы между двумя другими таблицами.

38
Q

Для чего нужны аннотации @OrderBy и @OrderColumn, чем они отличаются?

A

@OrderBy
Указывает порядок, в соответствии с которым должны располагаться элементы коллекций сущностей, базовых или встраиваемых типов при их извлечении из БД. Эта аннотация может использоваться с аннотациями @ElementCollection, @OneToMany, @ManyToMany.

  • При использовании с коллекциями базовых типов, которые имеют аннотацию @ElementCollection, элементы этой коллекции будут отсортированы в натуральном порядке.
  • Если это коллекция встраиваемых типов (@Embeddable), то используя точку(“.”) мы можем сослаться на атрибут внутри встроенного атрибута. Например, следующий код отсортируют адреса по названиям стран в обратном порядке:

@Embeddable
public class Address {

@Embedded
private City city
….
}
@ElementCollection
@OrderBy(“city.country DESC”)
private List<Address> addresses;

  • Если это коллекция сущностей, то у аннотации @OrderBy можно указать имя поля сущности, по которому сортировать эти самые сущности, если мы не укажем у @OrderBy параметр, то сущности будут упорядочены по первичному ключу.

@Entity
public class Task {
….
@OneToOne
private Employee supervisor;
…}
@ManyToMany
@OrderBy(“supervisor”)
private List<Task> tasks

  • В случае с сущностями доступ к полю по точке (“.”) не работает. Попытка использовать вложенное свойство, например @OrderBy (“supervisor.name”) повлечет Runtime Exceprtion.

@OrderColumn создает столбец в таблице, который используется для поддержания постоянного порядка в списке, но этот столбец не считается частью состояния сущности или встраиваемого класса.

Аннотация @OrderColumn может использоваться с аннотациями @ElementCollection, @OneToMany, @ManyToMany - указывается на стороне. В примере ниже Hibernate добавил в таблицу Employee_PhoneNumbers третий столбец PHONENUMBERS_ORDER, который и является результатом работы @OrderColumn:

Show Columns from Employee_PhoneNumbers
[EMPLOYEE_ID, BIGINT(19), NO, PRI, NULL]
[PHONENUMBERS, VARCHAR(255), YES, , NULL]
[PHONENUMBERS_ORDER, INTEGER(10), NO, PRI, NULL]
‘Select * FROM Employee_PhoneNumbers’
[1, 111-111,111, 0]
[1, 222-222,222, 1]
[2, 333-333-333, 0]
[2, 444-444-444, 1]
[2, 666-666-666, 2]
[3, 555-555-555, 0]

@OrderBy vs @OrderColumn Порядок, указанный в @OrderBy, применяется только в рантайме при выполнении запроса к БД, то есть в контексте персистентности,
в то время как при использовании @OrderColumn, порядок сохраняется в отдельном столбце таблицы и поддерживается при каждой вставке/обновлении/удалении элементов.

39
Q

Для чего нужна аннотация Transient?

A

аннотация используется для указания того, что данный атрибут сущности не должен сохраняться.

40
Q

Какие шесть видов блокировок (lock) описаны в спецификации JPA (или
какие есть значения у enum LockModeType в JPA)?

A

от самого ненадежного и быстрого, до самого надежного и медленного:

NONE — без блокировки
OPTIMISTIC — оптимистическая блокировка,
OPTIMISTIC_FORCE_INCREMENT — оптимистическая блокировка с принудительным увеличением поля версионности,
PESSIMISTIC_READ — пессимистичная блокировка на чтение,
PESSIMISTIC_WRITE — пессимистичная блокировка на запись (и чтение),
PESSIMISTIC_FORCE_INCREMENT — пессимистичная блокировка на запись (и чтение) с принудительным увеличением поля версионности.

Оптимистичное блокирование предполагает, что параллельно выполняющиеся транзакции редко обращаются к одним и тем же данным и позволяет им спокойно и свободно выполнять любые чтения и обновления данных. Но при окончании транзакции производится проверка, изменились ли данные в ходе её выполнения, если да, транзакция обрывается и выбрасывается исключение.

Оптимистичное блокирование в JPA реализовано путём внедрения в сущность специального поля версии:

@Entity
public class Company extends AbstractIdentifiableObject {
@Version
private long version;

private String name;

@ManyToMany(mappedBy = "workingPlaces")
private Collection<Person> workers;}

Поле, аннотирование @Version, может быть целочисленным или временнЫм. При завершении транзакции, если сущность была оптимистично заблокирована, будет проверено, не изменилось ли значение @Version кем-либо ещё, после того как данные были прочитаны, и, если изменилось, будет выкинуто OptimisticLockException. Использование этого поля позволяет отказаться от блокировок на уровне базы данных и сделать всё на уровне JPA, улучшая уровень конкурентности.

JPA поддерживает два типа оптимистичной блокировки:

LockModeType.OPTIMISTIC — блокировка на чтение, которая работает, как описано выше: если при завершении транзакции кто-то извне изменит поле @Version, то транзакция автоматически будет откачена и будет выброшено OptimisticLockException. Увеличивает version призаписи

LockModeType.OPTIMISTIC_FORCE_INCREMENT — блокировка на запись. Ведёт себя как и блокировка на чтение, но при этом увеличивает значение поля @Version после каждого коммита, независимо от того, была ли запись

Обе блокировки ставятся путём вызова метода lock() у EntityManager, в который передаётся сущность, требующая блокировки и уровень блокировки:

EntityManager em = entityManagerFactory.createEntityManager();
em.lock(company1, LockModeType.OPTIMISTIC);
em.lock(company2, LockModeType.OPTIMISTIC_FORCE_INCREMENT);
Блокировка будет автоматически снята при завершении транзакции, снять её до этого вручную невозможно.

Пессимистичное блокирование напротив, ориентировано на транзакции, которые постоянно или достаточно часто конкурируют за одни и те же данные и поэтому блокирует доступ к данным превентивно, в тот момент когда читает их. Другие транзакции останавливаются, когда пытаются обратиться к заблокированным данным и ждут снятия блокировки (или кидают исключение).
Пессимистичное блокирование выполняется на уровне базы и поэтому не требует вмешательств в код сущности. Так же, как и в случае с оптимистичным блокированием, поддерживаются блокировки чтения и записи:

LockModeType.PESSIMISTIC_READ — данные блокируются в момент чтения и это гарантирует, что никто в ходе выполнения транзакции не сможет их изменить. Остальные транзакции, тем не менее, смогут параллельно читать эти данные. Использование этой блокировки может вызывать долгое ожидание блокировки или даже выкидывание PessimisticLockException.

LockModeType.PESSIMISTIC_WRITE — данные блокируются в момент записи и никто с момента захвата блокировки не может в них писать и не может их читать до окончания транзакции, владеющей блокировкой. Использование этой блокировки может вызывать долгое ожидание блокировки.

Кроме того, для сущностей с полем, аннотированным @Version, существует третий вариант пессимистичной блокировки: LockModeType.PESSIMISTIC_FORCE_INCREMENT — ведёт себя как LockModeType.PESSIMISTIC_WRITE, но в конце транзакции увеличивает значение поля @Version, даже если фактически сущность не изменилась. Накладываются пессимистичные блокировки так же как и оптимистичные, вызовом метода lock():

em.lock(company1, LockModeType.PESSIMISTIC_READ);
em.lock(company2, LockModeType.PESSIMISTIC_WRITE);
em.lock(company3, LockModeType.PESSIMISTIC_FORCE_INCREMENT);

Снимаются они тоже автоматически, по завершению транзакции.

Следующие публичные методы EntityManager-а могут использоваться для наложения блокировок:

void lock(Object entity, LockModeType lockMode)
void lock(Object entity, LockModeType lockMode, Map<String, Object>
properties)
<T> T find(Class<T> entityClass, Object primaryKey, LockModeType
lockMode)
<T> T find(Class<T> entityClass, Object primaryKey, LockModeType
lockMode, Map<String, Object> properties)
void refresh(Object entity, LockModeType lockMode)
void refresh(Object entity, LockModeType lockMode, Map<String, Object>
properties)
41
Q

Какие два вида кэшей (cache) вы знаете в JPA и для чего они нужны?

A
  • first-level cache (кеш первого уровня) кеширует данные одной транзакции;
  • second-level cache (кеш второго уровня) кэширует данные транзакций от одной фабрики сессий. Провайдер JPA может, но не обязан реализовывать работу с кешем второго уровня.

Кеш первого уровня – это кеш сессии (Session), который является обязательным, это и есть PersistenceContext. Через него проходят все запросы.
Если выполняем несколько обновлений объекта, Hibernate старается отсрочить (насколько это возможно) обновление этого объекта для того, чтобы сократить количество выполненных запросов в БД.
Например, при пяти обращении к одному и тому же объекту из БД в рамках
одного persistence context, запрос в БД будет выполнен один раз, а остальные четыре загрузки будут выполнены из кеша.

Особенности кеша первого уровня:
* включен по умолчанию, его нельзя отключить;
* связан с сессией (контекстом персистентности), то есть разные сессии видят только объекты из своего кеша и не видят объекты, находящиеся в кешах других сессий;
* при закрытии сессии PersistenceContext очищается – кешированные объекты, находившиеся в нем, удаляются;
* при первом запросе сущности из БД она загружается в кеш, связанный с этой сессией;
* если в рамках этой же сессии снова запросим эту же сущность из БД, то она будет загружена из кеша и повторного SQL-запроса в БД сделано не будет;
* сущность можно удалить из кеша сессии методом evict(), после чего следующая попытка получить эту же сущность повлечет обращение к базе данных;
* метод clear() очищает весь кеш сессии.

Если кеш первого уровня привязан к объекту сессии, то кеш второго уровня привязан к объекту-фабрике сессий (Session Factory object), поэтому кеш второго уровня доступен одновременно в нескольких сессиях или контекстах персистентности. Кеш второго уровня требует некоторой настройки и поэтому не включен по умолчанию. Настройка кеша заключается в конфигурировании реализации кеша и разрешения сущностям быть закешированными.
Hibernate не реализует сам никакого in-memory сache, а использует существующие реализации кешей.

42
Q

Как работать с кешем 2 уровня?

A

Чтение из кеша второго уровня происходит только в том случае, если нужный объект не был найден в кеше первого уровня.

Hibernate поставляется со встроенной поддержкой стандарта кеширования Java JCache и сам не реализует кэш, а использует провайдеров:
Для Hibernate требуется только реализация интерфейса org.hibernate.cache.spi.RegionFactory, который инкапсулирует все детали, относящиеся к конкретным провайдерам.

Что нужно сделать:
1) добавить мавен-зависимость кэш-провайдера нужной версии
2) включить кэш второго уровня и определить конкретного провайдера:
hibernate.cache.use_second_level_cache=true
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory

3) установить у нужных сущностей JPA-аннотацию @Cacheable, обозначающую, что сущность нужно кэшировать, и Hibernate-аннотацию @Cache, настраивающую детали кэширования, у которой в качестве параметра указать стратегию параллельного доступа (о которой говорится далее), например так:
@Entity
@Table(name = “shared_doc”)
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class SharedDoc{
private Set<User> users;
}

4) не обязательно устанавливать у сущностей JPA-аннотацию @Cacheable, если работаем с Hibernate напрямую, не через JPA.

5) чтобы кэш не “съел” всю доступную память, можно, например, ограничивать количество каждого типа сущностей, хранимых в кэше:
```

<ehcache>
<cache></cache>
</ehcache>

~~~

43
Q

Что такое JPQL/HQL и чем он отличается от SQL?

A

Hibernate Query Language (HQL) и Java Persistence Query Language (JPQL) являются объектно-ориентированными языками запросов, схожими по природе с SQL. JPQL – это адаптированный под JPA HQL .

JPQL – это язык запросов, практически такой же, как SQL, но вместо имен и колонок таблиц базы данных использует имена классов Entity и их атрибуты. В качестве параметров запросов используются типы данных атрибутов Entity, а не полей баз данных.
В отличие от SQL в JPQL есть автоматический полиморфизм, то есть каждый запрос к Entity возвращает не только объекты этого Entity, но и объекты всех его классов-потомков, независимо от стратегии наследования.
Чтобы исключить такое поведение используется функция TYPE в where условии (например
select * from Animal a where TYPE(a) IN(Animal, Cat) уже не вернет объекты класса Dog)

В JPA запрос представлен в виде javax.persistence.Query или javax.persistence.TypedQuery, полученных из EntityManager.

JOIN FETCH vs Join
При запросе JOIN emp.department dep возвращается только сам запрощенный объект. При запросе JOIN FETCH emp.department dep возвращается объект и связанные с ним сущности, в одном запросе.

44
Q

Что такое Criteria API и для чего он используется?

A

Для операций update, delete или других DDL манипуляций использовать Criteria API нельзя. Критерии используются только для выборки из базы данных в более объектно-ориентированном стиле.

Основные преимущества JPA Criteria API:
- ошибки могут быть обнаружены во время компиляции;
- позволяет динамически формировать запросы на этапе выполнения приложения.

Запросы на основе строк JPQL и запросы на основе критериев JPA одинаковы по производительности и эффективности.

45
Q

Расскажите про проблему N+1 Select и путях ее решения.

A

Проблема N+1 запросов возникает, когда получение данных из БД выполняется за N дополнительных SQL-запросов для извлечения тех же данных, которые могли быть получены при выполнении основного SQL-запроса.

рекомендации:
1) избегать bidirectional oneToOne
2) использовать LAZY fetch везде, где возможно
1. JOIN FETCH
И при FetchType.EAGER, и при FetchType.LAZY поможет JPQL-запрос с JOIN FETCH. Опцию «FETCH» можно использовать в JOIN (INNER JOIN или LEFT JOIN) для выборки связанных объектов в одном запросе вместо дополнительных запросов для каждого доступа к ленивым полям объекта.
Это лучший вариант решения для простых запросов (1-3 уровня вложенности связанных объектов).
select pc from PostComment pc join fetch pc.post p
2.@FetchProfile - подойдет для извлечения и работы с одной сущностью (em.find(User.class, id))
3. EntityGraph
Если нужно получить много данных через jpql-запрос, лучше всего использовать EntityGraph.

https://habr.com/ru/company/otus/blog/529692/

46
Q

Что такое EntityGraph? Как и для чего их использовать?

A

Основная цель JPA Entity Graph – улучшить производительность в рантайме при загрузке базовых полей сущности и связанных сущностей и коллекций.
Позволяет улучшить гибкость при подгрузке только нужных сущностей независимо от уровня вложенности.

RootGraph<User> userGraph = session.createEntityGraph(User.class);
userGraph.addAttributeNodes("company", "userChats");
SubGraph<UserChat> userChatsSubgraph =
userGraph.addSubgraph("userChats", UserChat.class);
userChatsSubgraph.addAttributeNodes("chat");

Map<String, Object> properties = Map.of(
				GraphSemantic.LOAD.getJpaHintName(), userGraph);
var user = session.find(User.class, 1L, properties);

https://habr.com/ru/company/haulmont/blog/451986/