Czy należy zamknąć WZP Entity Manager?

83

Mam metodę poniżej.

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

Czy powyższe użycie menedżera podmiotu jest w porządku? Czy trzeba je zamknąć? Proszę o wszelkie sugestie.

JR Galia
źródło
Nie, po prostu nie. Chyba że chcesz przecieków ...

Odpowiedzi:

131

Przypuszczam, że odpowiedź brzmi: to zależy .

Twój menedżer encji jest kluczem do uzyskania dostępu do kontekstu, w którym znajdują się jednostki. Jeśli Twoja aplikacja jest aplikacją JSE, musisz wziąć pod uwagę oczekiwaną długość życia w Twoim kontekście.

Rozważmy, że utworzysz menedżera encji na żądanie użytkownika. Tak więc, gdy będziesz zajmować się daną prośbą, będziesz mieć otwartego menedżera encji, a kiedy skończysz, zamknij ją.

W aplikacji JSE mogłeś pomyśleć, że chciałbyś, aby menedżer encji pozostawał otwarty przez całe życie aplikacji (zakładając, że nie masz do czynienia z dużymi ilościami danych), a następnie zamykasz ją, gdy aplikacja zostanie zamknięta.

Podsumowując, kiedy go otworzysz i kiedy zamkniesz, zależy całkowicie od Twojej strategii i projektu. Zamykasz go, gdy nie potrzebujesz już jednostek w jego kontekście.

W twoim przykładzie nie jest to oczywiste, ale ponieważ tworzysz EM w metodzie, powinieneś zamknąć go przed powrotem, w przeciwnym razie nie będziesz już mieć do niego dostępu (chyba że trzymasz go w jakimś rejestrze, czego nie widać w kodzie).

Jeśli go nie zamkniesz, twoje byty pozostaną dołączone, nawet po zakończeniu ich używania. Twój kontekst pozostanie żywy, nawet jeśli nie będziesz już mieć dostępu do swojego EM.

JPA Specyfikacja zawiera więcej szczegółów. W sekcji 7.7 Konteksty trwałości zarządzanej przez aplikację jest napisane:

Kiedy używany jest menedżer encji zarządzany przez aplikację, aplikacja współdziała bezpośrednio z fabryką menedżerów encji dostawcy trwałości w celu zarządzania cyklem życia menedżera encji oraz uzyskiwania i niszczenia kontekstów trwałości.

Wszystkie takie konteksty trwałości zarządzane przez aplikację mają rozszerzony zakres i mogą obejmować wiele transakcji.

EntityManagerFactory.createEntityManagerSposób i EntityManager closei isOpenmetody są używane do zarządzania cyklem życia zarządcy jednostki aplikacji zarządzane i jego skojarzony kontekst trwałości.

Rozszerzony kontekst trwałości istnieje od momentu, w którym menedżer encji został utworzony przy użyciu, EntityManagerFactory.createEntityManageraż do zamknięcia menedżera encji za pomocą EntityManager.close.

Rozszerzony kontekst trwałości uzyskany z menedżera jednostek zarządzanych przez aplikację jest autonomicznym kontekstem trwałości, którego nie jest propagowany wraz z transakcją.

[…] EntityManager.closeMetoda zamyka menedżera encji, aby uwolnić jego kontekst trwałości i inne zasoby. Po wywołaniu close aplikacja nie może wywoływać żadnych dalszych metod w EntityManagerinstancji, z wyjątkiem getTransactioni isOpen, lub IllegalStateExceptionzostanie zgłoszony. Jeśli metoda close jest wywoływana, gdy transakcja jest aktywna, kontekst trwałości pozostaje zarządzany do momentu zakończenia transakcji.

EntityManager.isOpenMetoda wskazuje, czy menedżer jednostka jest otwarta. isOpenMetoda zwraca true, dopóki menedżer jednostka została zamknięta. Aby rzeczywiście zrozumieć, jak to działa, konieczne jest zrozumienie relacji między kierownikiem jednostki a kontekstem.

Jak więc widzisz, menedżer encji jest publicznym interfejsem, za pośrednictwem którego uzyskujesz dostęp do swoich podmiotów, jednak podmioty te znajdują się w kontekście, dołączonym do menedżera encji. Zrozumienie cyklu życia różnych typów kontekstów odpowie na Twoje pytanie.

Konteksty trwałości mogą być różnych typów. W aplikacjach Java EE można mieć kontekst trwałości o zakresie transakcji lub kontekst rozszerzonej trwałości . W aplikacji JSE natura kontekstu jest kontrolowana przez programistę .

Kiedy pytasz o jednostkę do swojego menedżera encji, szuka encji w dołączonym kontekście, jeśli znajdzie jednostkę tam, a następnie zwraca ją, w przeciwnym razie pobiera jednostkę z bazy danych. Kolejne wywołania tej jednostki w kontekście zwrócą tę samą jednostkę.

Zakres transakcji

W aplikacji Java EE korzystającej z kontekstu trwałości o zasięgu transakcji, kiedy po raz pierwszy uzyskujesz dostęp do swojego menedżera encji, sprawdza, czy bieżąca transakcja JTA ma dołączony kontekst, jeśli nie ma jeszcze żadnego kontekstu, tworzony jest nowy kontekst i jest połączony z menedżerem encji. w tym kontekście. Następnie jednostka jest odczytywana z bazy danych (lub z pamięci podręcznej, jeśli istnieje) i umieszczana w kontekście. Kiedy transakcja się kończy (zatwierdzenie lub wycofanie), kontekst staje się nieważny, a wszystkie zawarte w nim encje zostają odłączone. To jest klasyczny scenariusz dla fasoli sesji bezstanowych.

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

Oznacza to również, że w zależności od tego, jak zaprojektujesz swoje transakcje, możesz otrzymać więcej niż jeden kontekst.

Kontekst rozszerzonej trwałości

W aplikacji Java EE ze stanowymi fasolami sesji możesz chcieć, aby kontekst przetrwał wiele wywołań fasoli, ponieważ nie lubisz zatwierdzać, dopóki ziarno nie zostanie oznaczone do usunięcia, prawda? W takich przypadkach musisz użyć rozszerzonego kontekstu trwałości. W takim przypadku kontekst trwałości jest tworzony, gdy jest potrzebny po raz pierwszy, ale nie stanie się nieważny, dopóki nie oznaczysz fasoli stanowej do usunięcia.

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

Oznacza to, że niezależnie od instancji menedżera encji, która zostanie wstrzyknięta do tego komponentu bean w kolejnych wywołaniach metod stanowych bean sesji, możesz mieć pewność, że zawsze będziesz mieć dostęp do tego samego kontekstu, a zatem nawet kolejne wywołania zwrócą ten sam przykład, ponieważ jest to ten sam kontekst.

Ponadto zmiany nie zostaną usunięte, dopóki fasola nie zostanie oznaczona do usunięcia lub nie zostanie przepłukana ręcznie.

Zarządzane przez aplikację

Zawsze możesz ręcznie utworzyć instancję fabryki menedżerów encji i menedżera encji. To jest to, co zwykle robisz w aplikacji JSE, prawda?

W przypadku tego rodzaju aplikacji zazwyczaj nie masz kontenera do obsługi transakcji JTA, prawda? Dlatego używasz transakcji lokalnych zasobów i jesteś odpowiedzialny za ręczne zatwierdzanie lub wycofywanie zmian.

W przypadku tego rodzaju aplikacji podczas tworzenia wystąpienia menedżera encji kontekst jest do niego automatycznie dołączany.

W zależności od aplikacji możesz zdecydować o utworzeniu globalnego menedżera encji, którego cykl życia jest powiązany z życiem samej aplikacji. To jest jeden menedżer podmiotu przez cały okres istnienia aplikacji. W takich przypadkach kontekst zostanie utworzony i zniszczony wraz z menedżerem encji.

Lub możesz utworzyć menedżera encji na rozmowę (tj. Transakcję) z użytkownikiem aplikacji. W tym przypadku zakres jest określany przez Ciebie, ale nadal Twój kontekst zostanie utworzony i zniszczony wraz z menedżerem encji.

Edwin Dalorzo
źródło
Świetna odpowiedź, ale muszę wiedzieć: kilkakrotne otwieranie i zamykanie EntityManagera podczas sesji ma wysoką wydajność? Utwórz wystąpienie i zamknij tylko raz lub utwórz wystąpienie / użyj / zamknij go w każdej operacji Crud bazy danych, które jest najlepszym podejściem? „to zależy” ok, ale musi mieć bardziej odpowiednie zastosowanie w większości przypadków użycia ..
tomrlh
4
@tomurlh Jeśli o mnie chodzi, koszt stworzenia pliku EntityManagermusi być znikomy. Z mojego punktu widzenia EntityManager to tylko abstrakcja do zajmowania się jednostką pracy bieżącej transakcji. Uważam, że tworzenie i niszczenie jednej na transakcję jest w porządku. Teraz ma to inne konsekwencje, ponieważ EntityManagerserwery jako transakcyjna pamięć podręczna dla twoich jednostek, a więc posiadające dobrze zdefiniowany zakres transakcji i właściwe postępowanie z jednostkami, mogą skorzystać z tej pamięci podręcznej.
Edwin Dalorzo
Metoda EntityManager.close zamyka menedżera encji, aby zwolnić kontekst trwałości. Co to jest kontekst trwałości?
gstackoverflow
Oznacza to również, że w zależności od tego, jak zaplanujesz transakcje, możesz otrzymać więcej niż jeden kontekst. Czy mógłbyś wyjaśnić jak?
gstackoverflow