Сохранить JPA EntityManager?

Я изучаю JPA, и общий шаблон в примерах выглядит следующим образом:

EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
// ....
em.getTransaction().commit();
em.close();

Теперь мне интересно, почему мы постоянно создаем и закрываем EntityManager, а не открываем его и начинаем новые транзакции? Каковы преимущества и издержки, связанные с его открытием и закрытием его все время?

Ответы

Ответ 1

Приходят на ум две причины, связанные с JPA:

  • EntityManager не гарантируется, что он является потокобезопасным по спецификации JPA. Поэтому портативные приложения JPA могут использовать EM только в одном потоке за раз. Идиома создания локально-локального метода и его закрытие до того, как он выходит из области действия, поощряет удержание ссылок на EM-ссылки.

  • ЭМ, использующая "расширенный" контекст сохранения устойчивости, поддерживает единственный контекст сохранения для всего своего существования. Это означает, что объекты перестают автоматически отключаться на commit(). Вместо этого они должны быть вручную отключены, иначе EM остается ответственным за их отслеживание.

Этот вопрос действительно представляет собой версию старого вопроса "когда нужно объединить объекты" в JPA. Это жесткий, но ответ, вероятно, "редко".

Эта старая статья developerWorks экспертом Java concurrency Брайаном Гетцем излагает суть. Суть: пулы имеют большой смысл для дорогостоящих объектов, таких как соединения с базой данных. Но для недолговечных, маленьких и быстро инициализирующих объектов, таких как EntityManager, объединение или какая-то другая форма долгосрочного хранения ссылок - это тяжелая продажа.

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

Ответ 2

Сохранение открытого диспетчера объектов препятствует его возврату в пул соединений.

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

В этом случае лучше иметь менеджеров с небольшим проживанием, например. открыть диспетчер сущностей в начале запроса и закрыть его в конце запроса (может быть сделано с помощью прослушивателей/перехватчиков..). Затем объекты становятся отсоединенными, и вы должны повторно присоединить их, если хотите снова использовать их (используя операцию слияния с менеджером сущностей).