Sollte JPA Entity Manager geschlossen werden?

83

Ich habe die Methode unten.

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

Ist die oben genannte Verwendung des Entity Managers in Ordnung? Oder ist es notwendig, sie zu schließen? Irgendwelche Vorschläge bitte.

JR Galia
quelle
Nein einfach nein. Es sei denn, Sie möchten Lecks ...

Antworten:

131

Ich nehme an, die Antwort lautet: Es kommt darauf an .

Ihr Entitätsmanager ist der Schlüssel, um Zugriff auf den Kontext zu erhalten, in dem sich Entitäten befinden. Wenn es sich bei Ihrer Anwendung um eine JSE-Anwendung handelt, müssen Sie die Lebenserwartung Ihres Kontexts berücksichtigen.

Angenommen, Sie erstellen einen Entitätsmanager pro Benutzeranforderung. Während Sie an einer bestimmten Anfrage teilnehmen, bleibt Ihr Entity Manager geöffnet. Wenn Sie damit fertig sind, schließen Sie ihn.

In einer JSE-Anwendung haben Sie möglicherweise in Betracht gezogen, dass Sie Ihren Entitätsmanager während der gesamten Lebensdauer der Anwendung offen halten möchten (vorausgesetzt, Sie haben nicht mit großen Datenmengen zu tun), und schließen ihn dann, wenn Ihre Anwendung heruntergefahren wird.

Fazit: Wann Sie es öffnen und wann Sie schließen, hängt ganz von Ihrer Strategie und Ihrem Design ab. Sie schließen es, wenn Sie die Entitäten in ihrem Kontext nicht mehr benötigen.

In Ihrem Beispiel ist dies nicht offensichtlich. Da Sie jedoch die EM in der Methode erstellen, sollten Sie sie vor der Rückkehr schließen, da Sie sonst keinen Zugriff mehr darauf haben (es sei denn, Sie behalten sie in einer Registrierung.) was im Code nicht ersichtlich ist).

Wenn Sie es nicht schließen, bleiben Ihre Entitäten auch dann verbunden, wenn Sie sie nicht mehr verwenden. Ihr Kontext bleibt auch dann am Leben, wenn Sie nicht mehr auf Ihre EM zugreifen können.

Die JPA-Spezifikation enthält weitere Details. In Abschnitt 7.7 Anwendungsverwaltete Persistenzkontexte heißt es:

Wenn ein anwendungsverwalteter Entitätsmanager verwendet wird, interagiert die Anwendung direkt mit der Entitätsmanagerfactory des Persistenzanbieters, um den Lebenszyklus des Entitätsmanagers zu verwalten und Persistenzkontexte abzurufen und zu zerstören.

Alle derartigen anwendungsverwalteten Persistenzkontexte haben einen erweiterten Umfang und können mehrere Transaktionen umfassen.

Die EntityManagerFactory.createEntityManagerMethode und die Methoden EntityManager closeund isOpenwerden verwendet, um den Lebenszyklus eines anwendungsverwalteten Entitätsmanagers und den zugehörigen Persistenzkontext zu verwalten.

Der erweiterte Persistenzkontext besteht ab dem Zeitpunkt, an dem der Entitätsmanager mit erstellt wurde, EntityManagerFactory.createEntityManagerbis der Entitätsmanager mit geschlossen wird EntityManager.close.

Ein erweiterter Persistenzkontext, der vom anwendungsverwalteten Entitätsmanager abgerufen wird, ist ein eigenständiger Persistenzkontext, der nicht mit der Transaktion weitergegeben wird.

[...] Die EntityManager.closeMethode schließt einen Entitätsmanager, um seinen Persistenzkontext und andere Ressourcen freizugeben. Nach dem Aufruf von close darf die Anwendung keine weiteren Methoden für die EntityManagerInstanz aufrufen, außer getTransactionund isOpen, oder das IllegalStateExceptionwird ausgelöst. Wenn die Methode close aufgerufen wird, während eine Transaktion aktiv ist, bleibt der Persistenzkontext verwaltet, bis die Transaktion abgeschlossen ist.

Die EntityManager.isOpenMethode gibt an, ob der Entitätsmanager geöffnet ist. Die isOpenMethode gibt true zurück, bis der Entitätsmanager geschlossen wurde. Um tatsächlich zu verstehen, wie dies funktioniert, ist es wichtig, die Beziehung zwischen dem Entitätsmanager und dem Kontext zu verstehen.

Wie Sie sehen, ist der Entitätsmanager die öffentliche Schnittstelle, über die Sie auf Ihre Entitäten zugreifen. Ihre Entitäten befinden sich jedoch in einem Kontext, der Ihrem Entitätsmanager zugeordnet ist. Das Verständnis des Lebenszyklus der verschiedenen Arten von Kontexten wird Ihre Frage beantworten.

Persistenzkontexte können unterschiedlicher Art sein. In Java EE-Anwendungen können Sie entweder einen Persistenzkontext mit Transaktionsbereich oder einen Kontext mit erweiterter Persistenz haben . In der JSE-Anwendung wird die Art des Kontexts vom Entwickler gesteuert .

Wenn Sie Ihrem Entitätsmanager eine Entität anfordern, sucht er nach der Entität in seinem angehängten Kontext. Wenn er die Entität dort findet, gibt er sie zurück. Andernfalls ruft er die Entität aus der Datenbank ab. Nachfolgende Aufrufe für diese Entität im Kontext geben dieselbe Entität zurück.

Transaktionsbereich

In einer Java EE-Anwendung, die den transaktionsbezogenen Persistenzkontext verwendet, wird beim ersten Zugriff auf Ihren Entitätsmanager geprüft, ob an die aktuelle JTA-Transaktion ein Kontext angehängt ist, wenn noch kein Kontext vorhanden ist, ein neuer Kontext erstellt und der Entitätsmanager verknüpft wird zu diesem Kontext. Dann wird die Entität aus der Datenbank gelesen (o aus dem Cache, falls vorhanden) und in den Kontext gestellt. Wenn Ihre Transaktion endet (Festschreiben oder Zurücksetzen), wird der Kontext ungültig und alle darin enthaltenen Entitäten werden getrennt. Dies ist das klassische Szenario für zustandslose Sitzungs-Beans.

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

Dies bedeutet auch, dass Sie je nach Gestaltung Ihrer Transaktionen möglicherweise mehr als einen Kontext haben.

Kontext mit erweiterter Persistenz

In einer Java EE-Anwendung mit Stateful Session Beans möchten Sie möglicherweise, dass der Kontext mehrere Bean-Aufrufe überlebt, da Sie erst festschreiben möchten, wenn die Bean zum Entfernen markiert wurde, oder? In diesen Fällen müssen Sie einen erweiterten Persistenzkontext verwenden. In diesem Fall wird der Persistenzkontext erstellt, wenn er zum ersten Mal benötigt wird. Er wird jedoch erst ungültig, wenn Sie die Stateful Bean zum Entfernen markieren.

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

Dies bedeutet, dass Sie unabhängig von der Instanz des Entitätsmanagers, die in nachfolgenden Aufrufen der Stateful Session Beans-Methoden in diese Bean eingefügt wird, sicher sein können, dass Sie immer auf denselben Kontext zugreifen und daher auch nachfolgende Aufrufe denselben zurückgeben Instanz, weil es der gleiche Kontext ist.

Außerdem werden Ihre Änderungen erst gelöscht, wenn die Bean zum Entfernen markiert ist oder Sie sie manuell spülen.

Anwendungsverwaltet

Sie können Ihre Entity Manager-Factory und Ihren Entity Manager jederzeit manuell instanziieren. Dies ist, was Sie normalerweise in einer JSE-Anwendung tun würden, stimmt das?

Für diese Art von Anwendungen haben Sie normalerweise keinen Container, um die JTA-Transaktionen zu verarbeiten, oder? Sie verwenden also ressourcenlokale Transaktionen und sind dafür verantwortlich, Änderungen manuell festzuschreiben oder zurückzusetzen.

Bei dieser Art von Anwendung wird beim Instanziieren Ihres Entitätsmanagers automatisch ein Kontext angehängt.

Abhängig von Ihrer Anwendung können Sie einen globalen Entitätsmanager erstellen, dessen Lebenszyklus an die Lebensdauer der Anwendung selbst gebunden ist. Dies ist ein einzelner Entitätsmanager für die gesamte Lebensdauer der Anwendung. In diesem Fall wird Ihr Kontext mit Ihrem Entitätsmanager erstellt und zerstört.

Sie können auch einen Entitätsmanager pro Konversation (dh Transaktion) mit Ihrem Anwendungsbenutzer erstellen. Der Umfang wird in diesem Fall von Ihnen festgelegt. Ihr Kontext wird jedoch mit Ihrem Entitätsmanager erstellt und zerstört.

Edwin Dalorzo
quelle
Gute Antwort, aber ich muss wissen: EntityManager mehrmals während einer Sitzung öffnen und schließen, hat eine hohe Leistung? Nur einmal instanziieren und schließen oder in jeder Datenbank-Crud-Operation instanziieren / verwenden / schließen. Was ist der beste Ansatz? "es kommt darauf an" ok, muss aber für die meisten Anwendungsfälle besser geeignet sein.
Tomrlh
4
@tomurlh Für mich müssen die Kosten für die Erstellung des EntityManagervernachlässigbar sein. Aus meiner Sicht ist der EntityManager nur eine Abstraktion, um die Arbeitseinheit der aktuellen Transaktion zu behandeln. Ich glaube, es ist vollkommen in Ordnung, eine pro Transaktion zu erstellen und zu zerstören. Jetzt hat dies andere Auswirkungen, da die EntityManagerServer als Transaktionscache für Ihre Entitäten und daher über einen genau definierten Transaktionsbereich und den ordnungsgemäßen Umgang mit Entitäten diesen Cache nutzen können.
Edwin Dalorzo
Die EntityManager.close-Methode schließt einen Entitätsmanager, um seinen Persistenzkontext freizugeben. Was ist ein Persistenzkontext?
Gstackoverflow
Dies bedeutet auch, dass Sie je nach Gestaltung Ihrer Transaktionen möglicherweise mehr als einen Kontext haben. Können Sie erklären, wie?
gstackoverflow