2012-06-16 10 views

Antwort

11

Obwohl EntityManager Implementierungen selbst sind nicht Thread-sicher die Java EE Container spritzt eine Proxy, die Delegierten alle Methoden Anrufungen einer Transaktion gebunden EntityManager. Daher arbeitet jede Transaktion mit ihrer eigenen Instanz EntityManager. Dies gilt für mindestens den kontextbezogenen Persistenzkontext (Standardeinstellung).

Wenn Container eine neue Instanz von EntityManager in jeder Bohne injizieren würde die unten nicht funktionieren würde:

@Stateless 
public class Repository1 { 
    @EJB 
    private Repository2 rep2; 

    @PersistenceContext(unitName="blah", type = PersistenceContextType.TRANSACTION) 
    private EntityManager em; 

    @TransactionAttribute 
    public void doSomething() { 
     // Do something with em 
     rep2.doSomethingAgainInTheSameTransaction(); 
    } 
} 

@Stateless 
public class Repository2 { 
    @PersistenceContext(unitName="blah", type = PersistenceContextType.TRANSACTION) 
    private EntityManager em; 

    @TransactionAttribute 
    public void doSomethingAgainInTheSameTransaction() { 
     // Do something with em 
    } 
} 

doSomething-> doSomethingAgainInTheSameTransaction Aufruf geschieht in einer einzigen Transaktion und daher müssen die Bohnen teilen das gleiche EntityManager. Tatsächlich teilen sie sich den gleichen Proxy EntityManager, die Aufrufe an den gleichen Persistenzkontext delegiert.

So sind Sie legale Nutzung EntityManager in Singleton Bohnen wie unten:

@Singleton 
@ConcurrencyManagement(ConcurrencyManagementType.BEAN) 
public class Repository { 
    @PersistenceContext(unitName="blah", type = PersistenceContextType.TRANSACTION) 
    private EntityManager em; 
} 

Ein weiterer Beweis dafür ist, dass es keine der Thread-Sicherheit in EntityManager javadoc jede Erwähnung ist. Während Sie innerhalb des Java EE Containers bleiben, sollten Sie sich nicht um den Parallelzugriff auf EntityManager kümmern..

+3

Beachten Sie, dass diese Antwort (obwohl akzeptiert wird) in der Tat nicht wahr ist, wie in einer anderen Antwort polbotinka erwähnt. Lesen Sie weiter, wenn Sie sich für "Thread-Sicherheit" mit 'Java EE EntityManager' interessieren. – Aquillo

16

Zu meiner großen Überraschung (nach Jahren der Verwendung in ) EntityManagerist Thread nicht sicher. Dies ist eigentlich verständlich, wenn Sie tiefer darüber nachdenken: EntityManager ist nur ein Wrapper um native JPA-Implementierung, z. Sitzung in Hibernate, die wiederum ist ein Wrapper um Verbindung. Das heißt, EntityManager kann nicht threadsicher sein, da es eine Datenbankverbindung/-transaktion darstellt.

Warum funktioniert es im Frühling? Weil es Ziel EntityManager in einem Proxy umschließt, im Prinzip unter Verwendung von ThreadLocal, lokale Referenz für jeden Thread beizubehalten. Dies ist erforderlich, da Spring-Anwendungen auf Singletons basieren, während EJB den Objektpool verwendet.

Und wie können Sie in Ihrem Fall damit umgehen? Ich weiß nicht , aber in EJB wird jede statuslose und statusbehaftete Session-Bean gepoolt, was bedeutet, dass Sie nicht wirklich Methode desselben EJB von mehreren Threads in der gleichen Zeit aufrufen können. Daher wird EntityManager niemals gleichzeitig verwendet. Das heißt, injizieren EntityManager ist sicher, zumindest in statuslose und Stateful Session-Beans.

jedoch Injektion EntityManager zu Servlets und Singletons Bohnen ist nicht sicher als möglicherweise mehr Threads sie gleichzeitig zugreifen können, mit der gleichen JDBC-Verbindung vermasselt.

Siehe auch

+2

Nizza Erklärung, aber Sie sind falsch, wenn die besagt, „in EJB jeder Session Bean gebündelt wird, bedeutet das kann man nicht wirklich eine Methode gleichen EJB aufrufen von mehreren Threads auf der gleichen Zeit“ - @Singleton EJB oder EJB mit Pool der Größe 1, die Bean-Concurrency verwaltet, kann mehrere Threads gleichzeitig EJB-Logik ausführen. –

+0

@ StevoSlavić: Nun, ich sage eigentlich "* injizierenden EntityManager zu [...] Singleton Bohnen ist nicht sicher *". Ich werde diesen Teil klären, wenn Singletons auch als Session Beans betrachtet werden. Können Sie die containergesteuerte Synchronisation für Stateless- und Stateful-Session-Beans deaktivieren? Ich weiß, dass Sie es nur für Singletons tun können ... –

8

Ich glaube, ich muss tiefer in das gehen, weil meine erste Antwort nicht absolut richtig war.

Ich werde auf JSR-220 verweisen. In Abschnitt 5.2 Abrufen einer EntityManager können Sie finden:

Ein Unternehmen Manager bei mehreren gleichzeitig ausgeführter Threads nicht mit anderen geteilt werden können. Auf Entitätsmanager kann nur in einer Single-Thread-Art zugegriffen werden.

Nun, das ist es. Sie können hier aufhören zu lesen und nie EntityManager in Singleton Bohnen verwenden, wenn nicht ordnungsgemäß synchronisiert.

Aber ich glaube, es gibt eine Verwirrung in der Spezifikation. Es gibt zwei verschiedene EntityManager Implementierungen. Die erste ist eine Provider-Implementierung (sprich Hibernate), die nicht zwingend threadsicher sein muss.

Auf der anderen Seite gibt es eine Container-Implementierung EntityManager. Das soll auch nicht wie oben beschrieben threadsicher sein. Die Implementierung des Containers fungiert jedoch als Proxy und delegiert alle Anrufe an den EntityManager des realen Providers.

So weiter in der Spezifikation in 5.9 Runtime Verträge zwischen dem Container und Persistenz Provider:

Für die Verwaltung einer Transaktion-scoped Persistenzkontext, wenn kein EntityManager ist bereits mit der zugehörigen JTA-Transaktion: Der Container erstellt einen neuen Entitätsmanager, indem er EntityManagerFactory.createEntityManager aufruft, wenn der erste Aufruf von ein Entitätsmanager mit PersistenceContextType.TRANSACTION innerhalb des Bereichs von a auftritt Geschäftsmethode, die in der Transaktion JTA ausgeführt wird.

Dies bedeutet wiederum, dass es eine andere EntityManager Instanz sein für jede Transaktion gestartet. Der Code, der eine EntityManager schafft sicher nach 5.3:

Methods der EntityManagerFactory Schnittstelle THREAD sind.

Aber was, wenn es ein EntityManager mit JTA Transaktion verbunden ist? Der Code, der einen EntityManager verknüpft, der mit der aktuellen JTA-Transaktion verknüpft ist, ist laut Spezifikation möglicherweise nicht sicher.

Aber ich kann nicht wirklich eine Anwendungsserverimplementierung denken, die korrekt mit EntityManager funktioniert, injiziert in statusfreie Beans und nicht korrekt innerhalb von Singletons.

Also meine Schlussfolgerungen sind:

  1. Wenn Sie die JSR-220 streng folgen wollen, dann EntityManager in Singletons verwenden nie den Zugang zu ihr, bis zu synchronisieren.
  2. Ich persönlich werde weiterhin EntityManager in Singleton verwenden, weil meine Anwendung Server-Implementierung perfekt damit arbeitet. Vielleicht möchten Sie Ihre Implementierung vorher überprüfen.
+0

Auf welchen Anwendungsserver beziehen Sie sich in Ihrem Abschlusspunkt 2? –

+0

Apache TomEE 1.5 – polbotinka

+0

wahrscheinlich können Sie tadellos thread Ihre Em in Singleton EJB verwenden, weil Sie das grundlegende Singleton-Verhalten für alle seine Methoden (Lock.Write) lassen, die alle Methoden erreichbar, wie sie einen synchronisierten Modifikator hatten. –