Чи слід закривати JPA Entity Manager?


83

У мене є метод нижче.

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

Чи добре згадане вище використання менеджера сутності? Або їх потрібно закрити? Будь-які пропозиції, будь ласка.



Ні, просто ні. Якщо ви не хочете витоків ...

Відповіді:


131

Я припускаю, що відповідь така: це залежить .

Менеджер сутності - це ключ до доступу до контексту, в якому перебувають сутності. Якщо ваша заявка є формою JSE, вам слід врахувати, яка тривалість життя вашого контексту.

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

У програмі JSE ви могли подумати, що хотіли б тримати менеджер сутності відкритим протягом усього життя програми (припустимо, ви не маєте справу з великими обсягами даних), а потім закриваєте її, коли ваша програма вимикається.

Підсумок, коли ви його відкриваєте і коли закриваєте, повністю залежить від вашої стратегії та вашого дизайну. Ви закриваєте його, коли вам більше не потрібні сутності в його контексті.

У вашому прикладі це не очевидно, але оскільки ви створюєте EM у методі, вам слід закрити його перед поверненням, інакше ви більше не матимете до нього доступу (якщо ви не зберігаєте його в якомусь реєстрі, що не видно в коді).

Якщо ви не закриєте його, ваші об’єкти залишатимуться прикріпленими навіть після того, як ви закінчите їх використання. Ваш контекст буде жити навіть тоді, коли ви більше не зможете отримати доступ до своєї ЕМ.

Специфікація JPA містить більше деталей. У розділі 7.7 Контексти стійкості, керовані додатками, сказано:

Коли використовується керований додатком менеджер сутності, додаток взаємодіє безпосередньо з фабрикою менеджера сутності постачальника стійкості для управління життєвим циклом менеджера сутності та отримання та знищення контекстів стійкості.

Усі такі контексти збереженості, керовані додатками, розширені за обсягом і можуть охоплювати кілька транзакцій.

EntityManagerFactory.createEntityManagerМетод і EntityManager closeта isOpenметоди використовуються для управління життєвим циклом менеджера суті додатки керованого і пов'язаний з ним контекст збереження.

Розширений контекст збереження існує з моменту, коли був створений EntityManagerFactory.createEntityManagerменеджер сутності, доки менеджер сутності не буде закритий за допомогою EntityManager.close.

Розширений контекст збереження, отриманий від керованого додатками менеджера сутності, є окремим контекстом збереження, який не поширюється з транзакцією.

[...] EntityManager.closeМетод закриває менеджер сутності, щоб звільнити його контекст постійності та інші ресурси. Після виклику close програма не повинна викликати будь-які подальші методи в EntityManagerекземплярі, крім getTransactionі isOpen, або IllegalStateExceptionбуде викинуто. Якщо метод закриття викликається, коли транзакція активна, контекст збереження залишається керованим до завершення транзакції.

EntityManager.isOpenМетод показує, чи відкритий керуючий об'єктом. isOpenМетод повертає істину , поки диспетчер об'єктів не був закритий. Щоб насправді зрозуміти, як це працює, життєво важливо зрозуміти взаємозв'язок між менеджером сутності та контекстом.

Отже, як ви можете бачити, менеджер сутності - це загальнодоступний інтерфейс, через який ви отримуєте доступ до своїх об’єктів, однак ваші об’єкти перебувають у контексті, приєднаному до вашого менеджера об’єктів. Розуміння життєвого циклу різних типів контекстів дасть відповідь на ваше запитання.

Контексти стійкості можуть бути різних типів. У додатках Java EE ви можете мати контекст збереження транзакцій або розширений контекст збереження . У додатку JSE характер контексту контролюється розробником .

Коли ви запитуєте сутність у свого менеджера сутності, вона шукає сутність у приєднаному контексті; якщо вона знаходить сутність там, вона повертає її, інакше вона отримує сутність із бази даних. Подальші виклики для цієї сутності в контексті повернуть ту саму сутність.

Обсяг транзакції

У програмі Java EE з використанням контексту збереження транзакцій, коли ви вперше отримуєте доступ до диспетчера сутності, він перевіряє, чи до поточної транзакції JTA приєднаний контекст, якщо ще немає жодного контексту, створюється новий контекст і пов'язаний диспетчер сутності. до цього контексту. Потім сутність читається з бази даних (o з кешу, якщо вона присутня) і поміщається в контекст. Коли ваша транзакція закінчується (фіксація або відкат), контекст стає недійсним, і будь-які сутності в ньому від'єднуються. Це класичний сценарій для сеансів без громадянства.

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

Це також означає, що в залежності від того, як ви розробляєте свої транзакції, у вас може виникнути більше одного контексту.

Контекст розширеної стійкості

У програмі Java EE із сеансовими компонентами, що містять статус, вам може сподобатися, що контекст переживає кілька викликів компонента, оскільки ви не любите фіксувати, поки компонент не буде позначений для видалення, чи не так? У цих випадках вам потрібно використовувати розширений контекст стійкості. У цьому випадку контекст збереження створюється тоді, коли він уперше необхідний, але він не стане недійсним, поки ви не позначите компонент із статусом для видалення.

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

Це означає, що, незалежно від екземпляру диспетчера сутності, який вводиться в цей компонент у наступних викликах методів фасолевих сеансів із увімкненим станом, ви можете бути впевнені, що завжди будете мати доступ до одного і того ж контексту, а отже, навіть наступні виклики повернуть те саме наприклад, тому що це той самий контекст.

Крім того, ваші зміни не будуть змиті, поки зерно не буде позначено для видалення або якщо ви вручну не змиєте їх.

Управління додатками

Ви завжди можете створити екземпляр вручну заводу менеджера об’єктів та менеджера об’єктів. Це те, що ти зазвичай робиш у програмі JSE, чи не так?

Для такого роду програм у вас зазвичай немає контейнера для обробки транзакцій JTA, так? Отже, ви використовуєте локальні транзакції та відповідаєте за ручне фіксацію або відкат змін.

Для цього типу програми, коли ви створюєте екземпляр менеджера сутності, до нього автоматично приєднується контекст.

Залежно від вашої програми, ви можете вирішити створити глобальний менеджер сутності, життєвий цикл якого пов’язаний із життям самої програми. Це єдиний менеджер сутності протягом усього життя програми. У цьому випадку ваш контекст буде створено та знищено разом із менеджером сутності.

Або ви можете створити менеджер сутності для кожної розмови (тобто транзакції) з користувачем вашого додатка. У цьому випадку сфера дії визначається вами, але все-таки ваш контекст буде створений та знищений за допомогою менеджера сутності.


Чудова відповідь, але мені потрібно знати: відкривати та закривати EntityManager кілька разів під час сеансу, чи висока вартість роботи? Примірник і закриття лише один раз, або створення / використання / закриття його в кожній грубій операції з базою даних, який найкращий підхід? "це залежить" добре, але для більшості випадків використання має бути більш підходящим використанням.
tomrlh

4
@tomurlh Щодо мене, то витрати на створення EntityManagerмусять бути незначними. З моєї точки зору, EntityManager - це просто абстракція, що стосується одиниці роботи поточної транзакції. Я вважаю, що цілком нормально створити та знищити одну для кожної транзакції. Тепер це має інші наслідки, оскільки EntityManagerсервери як кеш транзакцій для ваших сутностей, тому, маючи чітко визначений обсяг транзакцій та належну роботу з сутностями, можуть скористатися цим кешем.
Едвін Далорцо,

Метод EntityManager.close закриває менеджер сутності, щоб звільнити його контекст постійності. Що таке контекст стійкості?
gstackoverflow

Це також означає, що в залежності від того, як ви розробляєте свої транзакції, у вас може бути кілька контекстів. Не могли б ви пояснити як?
gstackoverflow
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.