Должен ли быть закрыт администратор JPA?

У меня есть метод ниже.

public Profile readUser(String email){
    EntityManager em = EMF.get().createEntityManager();
    return em.find(Profile.class, email);
}

Является ли вышеупомянутое использование диспетчера объектов в порядке? Или нужно закрыть em? Любые предложения, пожалуйста.

Ответ 1

Я полагаю, что ответ: это зависит.

Ваш менеджер объектов является ключом к получению доступа к контексту, в котором находятся сущности. Если ваше приложение является JSE-приложением, вы должны учитывать, какова продолжительность жизни вашего контекста.

Предположим, что вы создадите диспетчер сущностей для каждого запроса пользователя. Итак, пока вы посещаете данный запрос, вы оставите своего менеджера сущностей открытым, и когда вы закончите с ним, вы его закроете.

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

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

В вашем примере это не очевидно, но поскольку вы создаете EM в методе, вы должны закрыть его перед возвратом, иначе у вас больше не будет доступа к нему (если вы не храните его в каком-то реестре, что не очевидно в коде).

Если вы не закроете его, ваши объекты будут сохранены как прикрепленные, даже после того, как вы закончите использовать их. Ваш контекст будет сохранен, даже если вы больше не сможете получить доступ к своей EM.

JPA Specification содержит более подробную информацию. В разделе 7.7 Контексты сохранения приложений:

Когда используется менеджер объектов, управляемый приложениями, приложение взаимодействует непосредственно с менеджером сущностей поставщика сохранения factory для управления жизненным циклом менеджера объектов и получения и уничтожить контексты персистентности.

Все такие контексты персистентности, управляемые приложениями, расширены в и может охватывать несколько транзакций.

Метод EntityManagerFactory.createEntityManager и Методы EntityManager close и isOpen используются для управления жизненный цикл менеджера сущностей, управляемых приложениями, и связанных с ним контекст сохранения.

Расширенный контекст персистентности существует из точки, в которой менеджер сущностей был создан с использованием EntityManagerFactory.createEntityManager, пока менеджер закрыто с помощью EntityManager.close.

Расширенный контекст сохранения, полученный из управляемых приложениями диспетчер сущностей - это автономный контекст сохранения, это не распространяемый транзакцией.

[...] Метод EntityManager.close закрывает диспетчер объектов для освободить контекст персистентности и другие ресурсы. После звонка закрыть приложение не должно ссылаться на какие-либо дополнительные методы на EntityManager, кроме getTransaction и isOpen, или IllegalStateException будет выброшен. Если метод close вызывается, когда транзакция активна, сохраняется контекст сохранения до завершения транзакции.

Метод EntityManager.isOpen указывает, является ли диспетчер объектов открыт. Метод isOpen возвращает значение true до тех пор, пока менеджер были закрыты. Чтобы понять, как это работает, очень важно понять взаимосвязь между менеджером сущности и контекстом.

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

Контексты сохранения могут быть разных типов. В приложениях Java EE вы можете либо иметь контекст сохранения контекста транзакции, либо расширенный контекст сохранения. В приложении JSE характер контекста контролируется разработчиком.

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

сделка в области видимости

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

@PersistenceContext(unitName="EmplService")
EntityManager em;

Это также означает, что в зависимости от того, как вы разрабатываете свои транзакции, вы можете столкнуться с несколькими контекстами.

Контекст с расширенной стойкостью

В приложении Java EE с сеансом с состоянием beans вам может потребоваться, чтобы контекст выдержал несколько вызовов bean, так как вам не понравится совершать, пока bean не будет помечен для удаления, не так ли? В этих случаях вам нужно использовать расширенный контекст сохранения. В этом случае контекст персистентности создается, когда он в первую очередь необходим, но он не станет недействительным до тех пор, пока ваш маркер не удалит состояние bean.

@PersistenceContext(unitName="EmplService", type=PersistenceContextType.EXTENDED)

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

Кроме того, ваши изменения не будут очищены до тех пор, пока bean не будет отмечен для удаления или вы их вручную не очистите.

Применение управляемого

Вы всегда можете вручную создать диспетчер объектов factory вручную и ваш менеджер сущностей. Это то, что вы обычно делаете в приложении JSE, верно?

Для таких приложений у вас обычно нет контейнера для обработки транзакций JTA, так? Таким образом, вы используете локальные транзакции ресурсов, и вы несете ответственность за ручную фиксацию или откат изменений.

Для такого типа приложений, когда вы создаете экземпляр менеджера сущностей, контекст автоматически привязывается к нему.

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

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