Автор оригинала: Vlad Mihalcea.
При извлечении сущности также будут загружены все атрибуты. Это связано с тем, что каждый атрибут сущности неявно помечен аннотацией @Basic
, политикой выборки по умолчанию которой является FetchType.НЕТЕРПЕЛИВЫЙ
.
Однако стратегия выборки атрибутов может быть установлена в FetchType.LAZY
, в этом случае атрибут сущности загружается с помощью дополнительного оператора select при первом доступе.
@Basic(fetch = FetchType.LAZY)
Одной этой конфигурации недостаточно, поскольку для Hibernate требуется инструментарий байт-кода для перехвата запроса на доступ к атрибутам и выдачи дополнительной инструкции select по требованию.
При использовании плагина улучшения байт-кода Maven для свойства включить ленивую инициализацию
конфигурации должно быть установлено значение true
, как показано в следующем примере:
org.hibernate.orm.tooling hibernate-enhance-maven-plugin ${hibernate.version} true true enhance
При наличии этой конфигурации все классы сущностей JPA будут оснащены функцией ленивой выборки атрибутов. Этот процесс происходит во время сборки, сразу после компиляции классов сущностей из связанных с ними исходных файлов.
Механизм ленивой выборки атрибутов очень полезен при работе с типами столбцов, в которых хранятся большие объемы данных (например, BLOB
, CLOB
, VARBINARY
). Таким образом, сущность может быть извлечена без автоматической загрузки данных из базовых типов больших столбцов, что повышает производительность.
Чтобы продемонстрировать, как работает отложенная выборка атрибутов, в следующем примере будет использоваться Вложение
объект, который может хранить любой тип носителя (например, PNG, PDF, MPEG).
@Entity @Table(name = "attachment") public class Attachment { @Id @GeneratedValue private Long id; private String name; @Enumerated @Column(name = "media_type") private MediaType mediaType; @Lob @Basic(fetch = FetchType.LAZY) private byte[] content; //Getters and setters omitted for brevity }
Такие свойства, как идентификатор сущности, имя или тип носителя, должны быть с готовностью извлечены при каждой загрузке сущности. С другой стороны, содержимое медиафайла должно извлекаться лениво, только при доступе к нему с помощью кода приложения.
После инструментирования сущности Attachment
байт-код класса изменяется следующим образом:
@Transient private transient PersistentAttributeInterceptor $$_hibernate_attributeInterceptor; public byte[] getContent() { return $$_hibernate_read_content(); } public byte[] $$_hibernate_read_content() { if ($$_hibernate_attributeInterceptor != null) { this.content = ((byte[]) $$_hibernate_attributeInterceptor.readObject( this, "content", this.content)); } return this.content; }
Извлечение атрибута content
выполняется перехватчиком постоянных атрибутов
ссылки на объект, что позволяет загружать базовый столбец BLOB
только при первом вызове средства получения.
При выполнении следующего тестового случая:
Attachment book = entityManager.find( Attachment.class, bookId); LOGGER.debug("Fetched book: {}", book.getName()); assertArrayEquals( Files.readAllBytes(bookFilePath), book.getContent() );
Hibernate генерирует следующие SQL-запросы:
SELECT a.id AS id1_0_0_, a.media_type AS media_ty3_0_0_, a.name AS name4_0_0_ FROM attachment a WHERE a.id = 1 -- Fetched book: High-Performance Java Persistence SELECT a.content AS content2_0_ FROM attachment a WHERE a.id = 1
Потому что он помечен типом FetchType.Включено расширение байт-кода с отложенной
аннотацией и отложенной выборкой, столбец содержимое
не извлекается вместе со всеми другими столбцами, инициализирующими объект Вложение
. Только когда уровень доступа к данным пытается получить доступ к свойству content
, Hibernate выдает дополнительный выбор для загрузки этого атрибута.
Точно так же, как FetchType.ЛЕНИВЫЕ
ассоциации, этот метод подвержен N+1 проблемам с запросами , поэтому рекомендуется соблюдать осторожность. Одним из незначительных недостатков механизма улучшения байт-кода является то, что все свойства сущностей, а не только те, которые отмечены типом FetchType.LAZY
аннотации будут преобразованы, как показано ранее.
Другой подход, позволяющий избежать загрузки довольно больших столбцов таблицы, заключается в сопоставлении нескольких вложенных объектов с одной и той же таблицей базы данных.
Как сущность Вложение
, так и вложенная сущность Сводка вложений
наследуют все общие атрибуты от Базового вложения
суперкласса.
@MappedSuperclass public class BaseAttachment { @Id @GeneratedValue private Long id; private String name; @Enumerated @Column(name = "media_type") private MediaType mediaType; //Getters and setters omitted for brevity }
В то время как Краткое описание вложения
расширяет Базовое вложение
без объявления какого-либо нового атрибута:
@Entity @Table(name = "attachment") public class AttachmentSummary extends BaseAttachment {}
Сущность Вложение
наследует все базовые атрибуты из суперкласса Базовое вложение
и также отображает столбец содержимое
.
@Entity @Table(name = "attachment") public class Attachment extends BaseAttachment { @Lob private byte[] content; //Getters and setters omitted for brevity }
При извлечении Резюме вложения
вложенной сущности:
AttachmentSummary bookSummary = entityManager.find( AttachmentSummary.class, bookId);
Сгенерированная инструкция SQL не будет извлекать столбец content
:
SELECT a.id as id1_0_0_, a.media_type as media_ty2_0_0_, a.name as name3_0_0_ FROM attachment a WHERE a.id = 1
Однако при извлечении объекта Вложение
:
Attachment book = entityManager.find( Attachment.class, bookId);
Hibernate будет извлекать все столбцы из базовой таблицы базы данных:
SELECT a.id as id1_0_0_, a.media_type as media_ty2_0_0_, a.name as name3_0_0_, a.content as content4_0_0_ FROM attachment a WHERE a.id = 1
Для ленивой выборки атрибутов сущностей можно использовать либо расширение байт-кода, либо вложенные сущности. Хотя инструментарий байт-кода позволяет использовать только одну сущность в таблице, вложенные элементы более гибки и могут даже повысить производительность, поскольку они не требуют вызова перехватчика при чтении атрибута сущности.
Когда дело доходит до считывания данных, субъективные значения очень похожи на прогнозы DTO . Однако, в отличие от прогнозов DTO, субстанции могут отслеживать изменения состояния и передавать их в базу данных.