Автор оригинала: Vlad Mihalcea.
Один из моих читателей наткнулся на сообщение о сопоставлении JSON и спросил меня, можем ли мы лениво получить свойства JSON. Этот пост демонстрирует, как легко это можно сделать при использовании Hibernate в качестве поставщика JPA.
Как я уже объяснял ранее, НЕТЕРПЕЛИВАЯ выборка-это запах кода, и нетерпеливая загрузка ассоциаций очень вредит производительности приложения. Однако мы должны быть осторожны не только с ассоциациями. Базовые свойства сущности также могут вызывать проблемы с производительностью. В этом посте я собираюсь показать вам, как вы можете лениво извлекать свойства сущностей.
По умолчанию режим гибернации быстро загружает все свойства. Поэтому, если у вашей сущности много свойств или базовые столбцы относительно велики, при извлечении рассматриваемой сущности будет оказываться значительное влияние на производительность. В то время как ассоциации могут быть загружены лениво с помощью прокси, созданных во время выполнения, для основных свойств нам необходимо улучшить байт-код .
Чтобы расширить возможности загрузки объектов с помощью базового свойства “Ленивая загрузка”, свойство включить ленивую инициализацию
конфигурации должно быть явно установлено в true
:
org.hibernate.orm.tooling hibernate-enhance-maven-plugin ${hibernate.version} true enhance
Я собираюсь повторно использовать ту же модель домена, которая использовалась в сообщении о сопоставлении JSON . В принципе, мы хотим лениво извлекать все свойства JSON, потому что размер объекта JSON может быть довольно большим.
Объект Событие
имеет свойство местоположение
, в котором хранится объект JSON. Чтобы загрузить его лениво, нам нужно пометить это свойство аннотацией @Basic(fetch.LAZY)
:
@Entity(name = "Event") @Table(name = "event") public class Event extends BaseEntity { @Type(type = "jsonb") @Column(columnDefinition = "jsonb") @Basic(fetch = FetchType.LAZY) private Location location; public Location getLocation() { return location; } public void setLocation(Location location) { this.location = location; } }
Объект Участник
имеет свойство билет
, в котором хранится объект JSON, поэтому это свойство также аннотируется с помощью @Basic(fetch.LAZY)
:
@Entity(name = "Participant") @Table(name = "participant") public class Participant extends BaseEntity { @Type(type = "jsonb") @Column(columnDefinition = "jsonb") @Basic(fetch = FetchType.LAZY) private Ticket ticket; @ManyToOne(fetch = FetchType.LAZY) private Event event; public Ticket getTicket() { return ticket; } public void setTicket(Ticket ticket) { this.ticket = ticket; } public Event getEvent() { return event; } public void setEvent(Event event) { this.event = event; } }
Чтобы доказать, что ленивая загрузка свойств работает, мы собираемся извлечь объект Событие
и перейти к свойству местоположение
следующим образом:
Event event = entityManager.find(Event.class, eventHolder.get().getId()); LOGGER.debug("Fetched event"); assertEquals("Cluj-Napoca", event.getLocation().getCity());
При запуске приведенного выше тестового случая Hibernate генерирует следующие инструкции:
SELECT e.id AS id1_0_0_ FROM event e WHERE e.id = 1 -- Fetched event SELECT e.location AS location2_0_ FROM event e WHERE e.id = 1
Как вы можете видеть, первый запрос не извлекает свойство location, которое инициализируется только при первом переходе.
То же самое относится и к нашему Участнику
юридическому лицу:
Participant participant = entityManager.find(Participant.class, participantHolder.get().getId()); LOGGER.debug("Fetched participant"); assertEquals("ABC123", participant.getTicket().getRegistrationCode());
Спящий режим, генерирующий следующие инструкции SQL:
SELECT p.id AS id1_1_0_ , p.event_id AS event_id3_1_0_ FROM participant p WHERE p.id = 1 -- Fetched participant SELECT p.ticket AS ticket2_1_ FROM participant p WHERE p.id = 1
Извлечение свойств сущности лениво пригодится всякий раз, когда мы имеем дело с типами столбцов BLOB
, CLOB
, ДВОИЧНЫЙ
, ТЕКСТ
и JSON|/. По умолчанию все ленивые свойства инициализируются вместе, но это поведение можно настроить с помощью
@LazyGroup , как будет объяснено в следующем посте.