Статьи

JPA — Должен ли я стать ленивым экстремистом?

Когда вы говорили с разработчиками о сопоставлении объектов с реляционными базами данных, они очень часто жалуются на низкую производительность JPA, непредсказуемое поведение поставщиков JPA и т. Д. Обычно в какой-то момент разговора вы услышите: «Давайте вообще отбросим эту технологию, мы Я видел что-то гораздо лучшее на конференции в прошлом месяце. Мы будем использовать его в наших проектах вместо JPA и будем развивать их с радостью ». — Звучит знакомо? Нет ничего плохого в изучении новых технологий, на самом деле вы должны делать это постоянно, чтобы улучшить свои навыки и знания, но когда у вас возникнут проблемы с одной из них, вы выберете легкий путь к другой технологии или спросите себя: «Я правильно его использовать? Давайте посмотрим на пример использования JPA. Предположим, что у нас есть простая база данных, сопоставленная с сущностями:

и мы должны отобразить все имена сотрудников, независимо от их работодателя (и отдела). Нет ничего проще — простой запрос JPQL сделает это:

1
select employee from Employee employee order by employee.name

Многие разработчики заканчивают на этом этапе и отмечают вместе с друзьями еще один успешный запрос JPQL в своей жизни, но у некоторых из нас возникает странное ощущение, что что-то жуткое скрывается под блестящей поверхностью. SQL-запросы, произведенные поставщиком JPA (например, Hibernate), покажут правду:

01
02
03
04
05
06
07
08
09
10
11
12
13
select [...]  from EMPLOYEE employee0_ order by employee0_.EMPLOYEE_NAME
 
Nothing special, so far , but here comes the naked truth:
 
select [...] from DEPARTMENT department0_ left outer join EMPLOYER employer1_ on department0_.EMPLOYER_ID=employer1_.EMPLOYER_ID where department0_.DEPARTMENT_ID=?
 
select [...] from EMPLOYER employer0_ where employer0_.EMPLOYER_ID=?
 
select [...] from DEPARTMENT department0_ left outer join EMPLOYER employer1_ on department0_.EMPLOYER_ID=employer1_.EMPLOYER_ID where department0_.DEPARTMENT_ID=?
 
select [...] from DEPARTMENT department0_ left outer join EMPLOYER employer1_ on department0_.EMPLOYER_ID=employer1_.EMPLOYER_ID where department0_.DEPARTMENT_ID=?
 
select [...] from DEPARTMENT department0_ left outer join EMPLOYER employer1_ on department0_.EMPLOYER_ID=employer1_.EMPLOYER_ID where department0_.DEPARTMENT_ID=?

Какого черта?! Для чего эти запросы ?! — Ну, причина кроется в значениях атрибута выборки по умолчанию для аннотаций @ManyToOne , то есть EAGER . В моей базе данных есть 2 работодателя, один из них имеет 4 отдела, а второй нет. Когда сотрудник загружен, JPA-провайдер по умолчанию загружает все ассоциации EAGER (в нашем случае и отдел, и работодатель), поэтому у нас возникают дополнительные запросы. Как вы видите выше, поставщик JPA достаточно умен, чтобы загружать как работодателя, так и отдел сразу, когда это возможно.

Вы только что нашли волшебный JPQL-запрос, извлекающий все содержимое базы данных одновременно . Эта ситуация напоминает вам что-то в прошлом? Что мы можем с этим поделать? — Мой друг, все, что тебе нужно, — это лень. — Не пользуйся EAGER, если он действительно НЕ нужен (и помни, что аннотации @ManyToOne и @OneToOne используют его по умолчанию).

В этот момент вы можете назвать меня сумасшедшим или экстремистом лени и спросить: вы когда-нибудь сталкивались с LazyInitializationException , братан? Слышали ли вы обо всем беспорядке с проблемами с отложенной загрузкой? Ухудшение производительности и т. Д. Конечно, я так и сделал, но разве вы не думаете, что, если у нас возникнут такие проблемы с JPA, может быть, мы используем его неправильно ?! Обычно мы делаем в веб-приложениях представление или редактирование некоторых данных в пользовательском интерфейсе, и обычно это лишь небольшое подмножество свойств конкретных объектов. Для этого необходимо извлечь дерево сущностей из базы данных — не задумываясь, мы просим Entity Manager: дать мне всех сотрудников, отсортированных по имени, со всеми связанными сущностями, а затем жаловаться на снижение производительности! Нам все равно, что мы получим из базы данных, потому что Entity Manager сделает за нас работу осла. Мы получаем LazyInitializationException , ну и что! Мы будем использовать Open Entity Manager в шаблоне View и заставим замолчать это глупое исключение!

Дай мне передохнуть! Тебе не кажется, что это тупик? — Пора что-то менять. Существуют сложные методы, которые вы можете использовать в своих проектах, например, CQRS , наряду с возможностями, уже существующими в JPA, которые могут помочь вам изменить плохие манеры, описанные мной в этом посте.

Несколько ссылок на десерт:

Ссылка: JPA — Должен ли я стать экстремистом лени? от нашего партнера JCG Михала Джастака в блоге Чернокнижника Мысли .