Injizieren von EntityManager Vs. EntityManagerFactory

70

Eine lange Frage, bitte nehmen Sie sie mit.

Wir verwenden Spring + JPA für eine Webanwendung. Mein Team debattiert über Injektion EntityManagerFactoryin den GenericDAO(DAO basierend auf Generics etwas über die von AppFuse vorgesehen Linien, wissen wir nicht verwenden , JpaDaosupportüber die Injektion aus irgendeinem Grund) ein EntityManager. Wir verwenden "anwendungsverwaltete Persistenz".

Die Argumente gegen das Injizieren von a EntityManagerFactorysind, dass es zu schwer ist und daher nicht benötigt wird, das EntityManagertut, was wir brauchen. Da Spring für jede Webanforderung eine neue Instanz eines DAO erstellen würde (ich bezweifle dies), treten keine Parallelitätsprobleme auf, da dieselbe EntityManagerInstanz von zwei Threads gemeinsam genutzt wird.

Das Argument für die Injektion von EFM ist, dass es eine gute Praxis ist, eine Fabrik im Griff zu haben.

Ich bin mir nicht sicher, welcher Ansatz der beste ist. Kann mich bitte jemand aufklären?

SB.
quelle
3
Ich verstehe weiter, dass Spring, wenn es den EntityManager injiziert, "Container-verwaltete Persistenz" ist und dass Spring den Entitymanager-Thread "sicher" macht. SB
SB.

Antworten:

51

Die Vor- und Nachteile der Injektion von EntityManagerFactory gegenüber EntityManager sind in den Spring-Dokumenten hier aufgeführt . Ich bin mir nicht sicher, ob ich das verbessern kann.

Wenn Sie das sagen, gibt es einige Punkte in Ihrer Frage, die geklärt werden sollten.

... Spring würde für jede Webanforderung eine neue Instanz eines DAO erstellen ...

Das ist nicht richtig. Wenn Ihr DAO eine Spring-Bean ist, handelt es sich um ein Singleton, sofern Sie es nicht über das scopeAttribut in der Bean-Definition anders konfigurieren . Ein DAO für jede Anfrage zu instanziieren wäre verrückt.

Das Argument für die Injektion von EMF ist, dass es eine gute Praxis ist, eine Fabrik im Griff zu haben.

Dieses Argument hält nicht wirklich Wasser. Nach allgemeiner bewährter Praxis sollte einem Objekt die Mindestanzahl an Mitarbeitern injiziert werden, die es für seine Arbeit benötigt.

Skaffman
quelle
1
Wenn Sie ihre Erklärung nicht verbessern können, könnten Sie sie vielleicht umschreiben? Es gibt viel in diesem Dokument und ich sehe nicht ganz, wo es "buchstabiert" ist. Außerdem ist es immer besser, eine Antwort zu haben, die für sich allein stehen kann, ohne dass Personen einem Link folgen müssen, um Ihre vollständige Antwort zu sehen.
Jasper
26

Ich lege nieder, was ich endlich gesammelt habe. Aus dem Abschnitt " Implementieren von DAOs basierend auf einfachem JPA " in der Frühjahrsreferenz:

EntityManagerFactory-Instanzen sind zwar threadsicher, EntityManager-Instanzen jedoch nicht. Der injizierte JPA-EntityManager verhält sich wie ein EntityManager, der aus der JNDI-Umgebung eines Anwendungsservers abgerufen wird, wie in der JPA-Spezifikation definiert. Es delegiert alle Aufrufe an den aktuellen Transaktions-EntityManager, falls vorhanden. Andernfalls wird pro Vorgang auf einen neu erstellten EntityManager zurückgegriffen, wodurch die Verwendung threadsicher wird.

Dies bedeutet, dass EntityManager-Instanzen gemäß den JPA-Spezifikationen nicht threadsicher sind. Wenn Spring sie jedoch verarbeitet, werden sie threadsicher gemacht.

Wenn Sie Spring verwenden, ist es besser, EntityManagers anstelle von EntityManagerFactory zu injizieren.

SB.
quelle
9

Ich denke, dies wurde bereits gut behandelt, aber nur um ein paar Punkte zu bekräftigen.

  • Wenn das DAO von Spring injiziert wird, ist es standardmäßig ein Singleton . Sie müssen den Bereich explizit auf Prototyp festlegen, um jedes Mal eine neue Instanz zu erstellen.

  • Der von @PersistenceContext injizierte Entity Manager ist threadsicher .

Davon abgesehen hatte ich einige Probleme mit einem Singleton-DAO in meiner Multithread-Anwendung. Am Ende machte ich das DAO zu einer instanziierten Bohne und das löste das Problem. Während die Dokumentation eines aussagt, möchten Sie Ihre Anwendung wahrscheinlich gründlich testen.

Nachverfolgen:

Ich denke, ein Teil meines Problems ist, dass ich benutze

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

Wenn Sie PersistenceContextType.EXTENDED verwenden, müssen Sie, wenn ich das richtig verstehe, die Transaktion manuell schließen. Weitere Informationen finden Sie in diesem Thread.

Ein weiteres Follow-up:

Die Verwendung eines instanziierten DAO ist eine äußerst schlechte Idee. Jede Instanz des DAO verfügt über einen eigenen Persistenz-Cache, und Änderungen an einem Cache werden von anderen DAO-Beans nicht erkannt. Entschuldigung für den schlechten Rat.

James McMahon
quelle
7

Ich fand, dass das Festlegen der Annotation @Repository Spring in unseren DAOs und das Verwalten von EntityManager durch Spring und das Injizieren durch Annotation @PersistenceContext der bequemste Weg ist, um alles flüssig zum Laufen zu bringen. Sie profitieren von der Thread-Sicherheit des freigegebenen EntityManager und der Ausnahmeübersetzung. Standardmäßig verwaltet der gemeinsam genutzte EntityManager Transaktionen, wenn Sie beispielsweise mehrere DAOs eines Managers kombinieren. Am Ende werden Sie feststellen, dass Ihre DAOs anämisch werden.

Gaël Marziou
quelle