Академический Документы
Профессиональный Документы
Культура Документы
JPA (Java Persistence API) это спецификация Java EE и Java SE, описывающая систему управления
сохранением java объектов в таблицы реляционных баз данных в удобном виде.
2. EntityManager это интерфейс, который описывает API для всех основных операций над Entity, получение данных и
других сущностей JPA. По сути главный API для работы с JPA. Основные операции:
1) Для операций над Entity: persist (добавление Entity под управление JPA), 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
4) Общие операции над EntityManager или всеми Entities: close, isOpen, getProperties, setProperty, clear.
3.
1) Entity класс должен быть отмечен аннотацией Entity или описан в XML файле конфигурации JPA,
2) Entity класс должен содержать public или protected конструктор без аргументов (он также может иметь
конструкторы с аргументами),
3) Entity класс должен быть классом верхнего уровня (top-level class),
4) Entity класс не может быть enum или интерфейсом,
5) Entity класс не может быть финальным классом (final class),
6) Entity класс не может содержать финальные поля или методы, если они участвуют в маппинге (persistent final
methods or persistent final instance variables),
7) Если объект Entity класса будет передаваться по значению как отдельный объект (detached object), например через
удаленный интерфейс (through a remote interface), он так же должен реализовывать Serializable интерфейс,
8) Поля Entity класс должны быть напрямую доступны только методам самого Entity класса и не должны быть
напрямую доступны другим классам, использующим этот Entity. Такие классы должны обращаться только к методам
(getter/setter методам или другим методам бизнес-логики в Entity классе),
9) Entity класс должен содержать первичный ключ, то есть атрибут или группу атрибутов которые уникально
определяют запись этого Entity класса в базе данных.
8. Встраиваемый (Embeddable) класс это класс который не используется сам по себе, только как часть одного или
нескольких Entity классов. Entity класс могут содержать как одиночные встраиваемые классы, так и коллекции таких
классов. Также такие классы могут быть использованы как ключи или значения map. Во время выполнения каждый
встраиваемый класс принадлежит только одному объекту Entity класса и не может быть использован для передачи
данных между объектами Entity классов (то есть такой класс не является общей структурой данных для разных
объектов). В целом, такой класс служит для того чтобы выносить определение общих атрибутов для нескольких Entity,
можно считать что JPA просто встраивает в Entity вместо объекта такого класса те атрибуты, которые он содержит.
Такие классы должны удовлетворять тем же правилам что Entity классы, за исключением того что они не обязаны
содержать первичный ключ и быть отмечены аннотацией Entity,
Embeddable класс должен быть отмечен аннотацией Embeddable или описан в XML файле конфигурации JPA.
9. Mapped Superclass это класс от которого наследуются Entity, он может содержать аннотации JPA, однако сам такой
класс не является Entity, ему не обязательно выполнять все требования установленные для Entity (например, он может
не содержать первичного ключа). Такой класс не может использоваться в операциях EntityManager или Query. Такой
класс должен быть отмечен аннотацией MappedSuperclass или соответственно описан в xml файле.
10. Какие три типа стратегии наследования мапинга (Inheritance Mapping Strategies) описаны в JPA?
В JPA описаны три стратегии наследования мапинга (Inheritance Mapping Strategies), то есть как JPA будет работать с
классами-наследниками Entity:
1) одна таблица на всю иерархию наследования (a single table per class hierarchy) — все entity, со всеми наследниками
записываются в одну таблицу, для идентификации типа entity определяется специальная колонка “discriminator
column”. Например, если есть entity Animals c классами-потомками Cats и Dogs, при такой стратегии все entity
записываются в таблицу Animals, но при это имеют дополнительную колонку animalType в которую соответственно
пишется значение «cat» или «dog».Минусом является то что в общей таблице, будут созданы все поля уникальные для
каждого из классов-потомков, которые будет пусты для всех других классов-потомков. Например, в таблице animals
окажется и скорость лазанья по дереву от cats и может ли пес приносить тапки от dogs, которые будут всегда иметь
null для dog и cat соответственно.
2) объединяющая стратегия (joined subclass strategy) — в этой стратегии каждый класс entity сохраняет данные в свою
таблицу, но только уникальные колонки (не унаследованные от классов-предков) и первичный ключ, а все
унаследованные колонки записываются в таблицы класса-предка, дополнительно устанавливается связь (relationships)
между этими таблицами, например в случае классов Animals (см.выше), будут три таблицы animals, cats, dogs, причем
в cats будет записана только ключ и скорость лазанья, в dogs — ключ и умеет ли пес приносить палку, а в animals все
остальные данные cats и dogs c ссылкой на соответствующие таблицы. Минусом тут являются потери
производительности от объединения таблиц (join) для любых операций.
3) одна таблица для каждого класса (table per concrete class strategy) — тут все просто каждый отдельный класс-
наследник имеет свою таблицу, т.е. для cats и dogs (см.выше) все данные будут записываться просто в таблицы cats и
dogs как если бы они вообще не имели общего суперкласса. Минусом является плохая поддержка полиморфизма
(polymorphic relationships) и то что для выборки всех классов иерархии потребуются большое количество отдельных
sql запросов или использование UNION запроса.
13. Для коллекций создаются отдельные таблицы, в некоторых случаях с добавлением столбца со значением ключа. С
сущностями объекты сохраняемой коллекции взаимодействуют с помощью связей (OneToMany, ManyToOne,
ManyToMany)
@ElementCollection
@OrderBy
Если у нашей сущности есть поле с коллекцией, то мы привыкли ставить над ним аннотации @OneToMany либо
@ManyToMany. Но данные аннотации применяются в случае, когда это коллекция других сущностей (entities). Если у
нашей сущности коллекция не других сущностей, а базовых или встраиваемых (embeddable) типов для этих случаев в
JPA имеется специальная аннотация @ElementCollection, которая указывается в классе сущности над полем коллекции.
Все записи коллекции хранятся в отдельной таблице, то есть в итоге получаем две таблицы: одну для сущности,
вторую для коллекции элементов.
@CollectionTable - позволяет редактировать таблицу с коллекцией, прочитать
15. Владелец связи — сущность, содержащая атрибут-объект владеемого класса. Поля владеемого класса отмечается
аннтоцией @JoinColumn(имя столбца) имя столбца в котором хранится ссылка на владеемую сущность
Во владеемом классе поле, содержащее объект класса-владельца помечается @One/ManyToOne/Many...
(имя_поля_класса-владельца). На объекты владеемого класса распространяются действия, совершаемые с объектом
класса-владельца, это называется каскадированием и настраивается параметром CascadeType
16. Каскадирование - это когда мы выполняем какое-то действие с целевой сущностью, то же самое действие будет
применено к связанной сущности.
JPA CascadeType:
ALL - распространяет все операции, включая специфичные для Hibernate, от родительского объекта к дочернему
объекту.
PERSIST - делает временный экземпляр постоянным. CascadeType.PERSIST передает операцию persist от
родительского объекта к дочернему объекту . Когда мы сохраняем личность лица, адрес также будет сохранена.
MERGE - операция слияния копирует состояние данного объекта в постоянный объект с тем же идентификатором.
CascadeType.MERGE передает операцию слияния от родителя к дочерней сущности.
REMOVE - удаляет строку, соответствующую объекту, из базы данных, а также из постоянного контекста.
DETACH - удаляет объект из постоянного контекста. Когда мы используем CascadeType.DETACH, дочерняя сущность
также будет удалена из постоянного контекста.
Hibernate CascadeType:
LOCK - повторно присоединяет сущность и связанную дочернюю сущность с постоянным контекстом снова.
REFRESH - повторно считывают значение данного экземпляра из базы данных. В некоторых случаях мы можем
изменить экземпляр после сохранения в базе данных, но позже нам нужно отменить эти изменения.
REPLICATE - используется, когда у нас более одного источника данных, и мы хотим, чтобы данные были
синхронизированы. С CascadeType.REPLICATE операция синхронизации также распространяется на дочерние объекты
всякий раз, когда выполняется над родительским объектом.
SAVE_UPDATE - распространяет ту же операцию на связанный дочерний объект. Это полезно, когда мы используем
специфичные для Hibernate операции, такие как save, update и saveOrUpdate.
18.
19.-23. persist()
• new → managed, и объект будет сохранен в базу при commit-е транзакции или в результате flush операций
• managed → операция игнорируется, однако зависимые Entity могут поменять статус на managed, если у них
есть аннотации каскадных изменений
• removed → managed
• detached → exception сразу или на этапе commit-а транзакции
remove()
• new → операция игнорируется, однако зависимые Entity могут поменять статус на removed, если у них есть
аннотации каскадных изменений и они имели статус managed
• managed → removed и запись объект в базе данных будет удалена при commit-е транзакции (также
произойдут операции remove для всех каскадно зависимых объектов)
• removed → операция игнорируется
• detached → exception сразу или на этапе commit-а транзакции,
merge()
• detached → либо данные будут скопированы в существующий managed entity с тем же первичным ключом,
либо создан новый managed в который скопируются данные
• new → будет создана новый managed entity, в который будут скопированы данные прошлого объекта
• managed → операция игнорируется, однако операция merge сработает на каскадно зависимые Entity, если их
статус не managed
• removed → exception сразу или на этапе commit-а транзакции,
refresh()
• managed → будут восстановлены все изменения из базы данных данного Entity, также произойдет refresh
всех каскадно зависимых объектов
• new, removed, detached → exception
detach()
• managed, removed → detached.
• new, detached → операция игнорируется
24. @Basic
@Basic — указывает на простейший тип маппинга данных на колонку таблицы базы данных. Также в параметрах
аннотации можно указать fetch стратегию доступа к полю и является ли это поле null или нет.
Самый простой тип сопоставления со столбцом базы данных. Базовая аннотация может быть применена к
постоянному свойству или переменной экземпляра любого из следующих типов: примитивные типы Java, оболочки
примитивных типов, String, BigInteger, BigDecimal, Date, Calendar, Time, Timestamp, byte[], Byte[], char[], Character[],
enums, и любой другой тип, который реализует java.io.Serializable.
Использование базовой аннотации является необязательным для постоянных полей и свойств этих типов. Если базовая
аннотация не указана для такого поля или свойства, то будут применяться значения по умолчанию базовой
аннотации.
@Basic vs @Column:
1. Атрибуты @Basic применяются к сущностям JPA, тогда как атрибуты @Column применяются к столбцам базы
данных.
2. @Basic имеет атрибут optional, который говорит о том, может ли поле объекта быть null или нет; с другой стороны
атрибут nullable аннотации @Column указывает, может ли соответствующий столбец в таблице быть null.
3. Мы можем использовать @Basic, чтобы указать, что поле должно быть загружено лениво.
4. Аннотация @Column позволяет нам указать имя столбца в таблице и ряд других свойств:
a. insertable/updatable - можно ли добавлять/изменять данные в колонке, по умолчанию true;
b. length - длина, для строковых типов данных, по умолчанию 255.
Коротко, в коламн мы заем констраинтс, а в басик ФЕТЧ ТАЙП"
25. @Column нужна чтобы указать детали столбца в таблице.
@Column аннотации имеет много атрибутов, такие как name, length, nullable и unique.
Элемент name указывает имя столбца в таблице. Элемент length указывает его длину. атрибут nullable определяет,
является ли элемент обнуляемым, и unique атрибут определяет, является ли уникальным столбец.
Если мы не укажем эту аннотацию, имя поля будет считаться именем столбца в таблице.
26. @Access: определяет тип доступа, поле или свойство. Поле — является значением по умолчанию и если нужно,
чтобы hibernate использовал методы getter/setter, то их необходимо задать для нужного свойства.
27. @Cacheable это аннотация JPA и позволяет объекту быть закэшированным. Hibernate поддерживает эту аннотацию
в том же ключе.
28. Аннотация @Embeddable позволяет указать класс, экземпляры которого хранятся как внутренняя часть сущности-
владельца. Эта аннотация не имеет атрибутов .
Аннотация @Embedded используется для указания постоянного поля или свойства сущности, значение которой
является экземпляром встраиваемого класса. По умолчанию определения столбцов, указанные в классе @Embeddable ,
применяются к таблице объекта-владельца, но их можно переопределить с помощью @AttributeOverride
30. С помощью @Id мы указываем первичный ключ (Primary Key) данного класса.
Типы переменных для @Id: примитивные и примитивные типы-оболочки, String, Date, BigDecimal, BigInteger.
31. @JoinColumn
Указывает столбец для присоединения к связной сущности или коллекции элементов. Если сама аннотация
@JoinColumn имеет значение по умолчанию, то предполагается наличие одного столбца соединения и применяются
значения по умолчанию.
https://docs.oracle.com/javaee/7/api/javax/persistence/JoinColumn.html
32. @OrderBy
Определяет порядок элементов коллекции, оцениваемой ассоциацией или коллекцией элементов, в тот момент,
когда ассоциация или коллекция извлекаются.
https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/OrderBy.html
@OrderBy могут быть применены к элементу коллекции. Когда OrderBy применяется к коллекции элементов базового
типа, порядок будет по значению базовых объектов, а имя свойства или поля не используется. При указании порядка
для коллекции элементов встраиваемого типа необходимо использовать точечную нотацию для указания атрибута
или атрибутов, которые определяют порядок.
Указанный порядок @OrderBy применяется только во время выполнения при получении результата запроса.
34. Блокировки — механизм, регулирующий работу с данными в БД, когда к ним обращаются две и более транзакции
одновременно. Есть два подхода к организации работы блокировок — оптимистический и пессимистический:
Оптимистичный подход предполагает, что параллельно выполняющиеся транзакции редко обращаются к одним и
тем же данным и позволяет им спокойно и свободно выполнять любые чтения и обновления данных. Но, при
окончании транзакции, то есть записи данных в базу, производится проверка, изменились ли данные в ходе
выполнения данной транзакции и если да, транзакция обрывается и выбрасывается исключение.
Пессимистичный подход напротив, ориентирован на транзакции, которые постоянно или достаточно часто
конкурируют за одни и те же данные и поэтому блокирует доступ к данным превентивно, в тот момент когда читает
их. Другие транзакции останавливаются, когда пытаются обратиться к заблокированным данным и ждут снятия
блокировки (или кидают исключение).
Разница в том, что в первом случае обеспечивается более высокий уровень конкурентности при доступе к базе,
который оплачивается необходимостью переповтора транзакций, в случае коллизии. Во втором случае транзакции
гарантируется, что только она будет иметь полный доступ к данным, но за счёт понижения уровня конкурентности и
затрат времени на ожидание блокировки.
Блокировок же есть 6 видов:
- OPTIMISTIC
- PESSIMISTIC_READ
- PESSIMISTIC_WRITE
- PESSIMISTIC_FORCE_INCREMENT
L1 – кэширует данные только одной транзакции, всегда включен и не может быть отключен. Не потокобезопасен.
Очищается методом clear()
L2 – кеширует данные более чем одной сессии/транзакции. Кэш второго уровня создается в области фабрики
EntityManagerFactory и доступен для использования во всех EntityManager, которые создаются с использованием этой
конкретной фабрики.
36. hibernate.cache.use_second_level_cache=true
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
Чтобы сделать объект пригодным для кэширования второго уровня, мы помечаем его аннотацией @Cache или
Hibernate также поддерживает QueryCache, который может хранить результаты запроса. Вам необходимо активировать его в
файле persistence.xml, установив для параметра
hibernate.cache.use_query_cache=true
и определив
hibernate.cache.region.factory_class
Кроме того, вам также необходимо активировать кэширование для конкретного запроса, для которого вы хотите кэшировать
результаты, вызывая
setCacheable(true) хранит id и по ним ищет объекты по нимв кэше объекты****
37. HQL – Hibernate Query Language – язык запросов Hibernate. SQL-подобный язык, вместо имен и столбцов таблиц
баз данных использует имена Entity-классов и их атрибудты. Поддерживает плиморфизм. Нестандартизован.
JPQL – Java Persistence Query Language – стандартизованный язык запросов, подобный HQL.
38. Hibernate Criteria API является более объектно-ориентированным для запросов, которые получают результат из
базы данных (DML). Для операций update, delete или других DDL манипуляций использовать Criteria API нельзя.
Критерии используются только для выборки из базы данных в более объектно-ориентированном стиле. Используется
для динамических запросов
Criteria API поддерживает проекцию, которую мы можем использовать для агрегатных функций вроде sum(), min(),
max() и т.д.
Criteria API может использовать ProjectionList для извлечения данных только из выбранных колонок.
Criteria API может быть использована для join запросов с помощью соединения нескольких таблиц, используя методы
Criteria API поддерживает выборку результатов согласно условиям (ограничениям). Для этого используется метод add()
Criteria API позволяет добавлять порядок (сортировку) к результату с помощью метода addOrder().
Criteria JPA – минус – не видно запросов, создается в некоторых случаях много объектов; низкая производительность
Допустим, у вас есть коллекция Car объектов (строк базы данных), и у каждого Car есть коллекция Wheel объектов
(также строк). Другими словами, Car→ Wheel это отношение 1-ко-многим.
Теперь предположим, что вам нужно пройтись по всем машинам, и для каждой распечатать список колес:
SELECT * FROM Cars;
И тогда для каждого Car:
SELECT * FROM Wheel WHERE CarId = ?
Другими словами, у вас есть один выбор для автомобилей, а затем N дополнительных выборов, где N - общее
количество автомобилей.
В качестве альтернативы можно получить все колеса и выполнить поиск в памяти:
SELECT * FROM Wheel
Это уменьшает количество обращений к базе данных с N+1 до 2. Большинство инструментов ORM предоставляют
несколько способов предотвратить выбор N+1.
https://stackoverflow.com/questions/97197/what-is-the-n1-selects-problem-in-orm-object-relational-mapping
Решения:
bidirectional
unidirectional OneToMany unidirectional ManyToone
solution OneToMany/ManyToOne
FetchMode.SUBSELECT + - - - +/-** -
EntityGraph + - + - + -
SqlResultSetMapping - - - + - -/+***
HibernateSpecificMapping - -* - + - +
* - если не используем аннотацию JoinColumn и оставляем связанную третью таблицу
** - работает только при выборке собственника с коллекцией зависимых сущностей
*** - работает только при выборке дочерней сущности с ссылкой на родительскую сущность
Выводы:
1. Лучшим вариантом решения N+1 проблемы для простых запросов (1-3 уровня вложенности связанных объектов)
будет join fetch и jpql запрос. Следует придерживаться тактики, когда мы выбираем из jpql и нативного запроса jpql
2. Если у нас имеется нативный запрос, и мы не заботимся о слабой связанности кода - то хорошим вариантом будет
использование Hibernate Specific Mapping. В противном случае стоит использовать @SqlResultSetMapping
3. В случаях, когда нам нужно получить по-настоящему много данных, и у нас jpql запрос - лучше всего использовать
EntityGraph
4. Если мы знаем примерное количество коллекций, которые будут использоваться в любом месте приложения -
можно использовать @BatchSize
Для этого существует EntityGraph API, используется он так: с помощью аннотации @NamedEntityGraph для Entity,
создаются именованные EntityGraph объекты, которые содержат список атрибутов у которых нужно поменять
fetchType на EAGER, а потом данное имя указывается в hits запросов или метода find. В результате fetchType атрибутов
Entity меняется, но только для этого запроса. Существует две стандартных property для указания EntityGraph в hit:
1) javax.persistence.fetchgraph — все атрибуты перечисленные в EntityGraph меняют fetchType на EAGER, все остальные
на LAZY
2) javax.persistence.loadgraph — все атрибуты перечисленные в EntityGraph меняют fetchType на EAGER, все остальные
сохраняют свой fetchType (то есть если у атрибута, не указанного в EntityGraph, fetchType был EAGER, то он и
останется EAGER)С помощью NamedSubgraph можно также изменить fetchType вложенных объектов Entity.
https://docs.google.com/document/d/1F5t0pjTb5KpCiSEwSEdbCneBmOxnd4eNInXTPsbAnck/edit?usp=sharing