2014-05-06 20 views
6

Ich habe eine Webanwendung, die ein seltsames Verhalten hat, wo ich nicht wirklich meinen Finger aufsetzen kann. Der Kern meines Problems besteht darin, dass die von meinen Ruheendpunkten zurückgegebenen Werte ein inkonsistentes Verhalten aufweisen. Wenn ich meine Anwendung starte, gibt meine Abfrage bei jedem Aufruf dieses Endpunkts dieselben Werte zurück. Wenn ich eine Entität aktualisiere, beginnt sich mein Entitätsmanager merkwürdig zu verhalten. Jetzt beginnt meine Abfrage unterschiedliche Ergebnisse zu liefern. Einmal werden alte Werte anstelle der Werte in der Datenbank zurückgegeben, oder meine Ergebnisliste enthält anstelle von Objekten Proxies (gemischt). enter image description herejpa2 wiederverwendet entityManager mit guice

Ich habe bestätigt, dass meine @transaction Methoden korrekt platziert sind und in meinem Debug-Stack Ich sehe die Transaktion Interceptor und das Unternehmen Manager pro Anfrage an das Backend erstellt wird (also keine guice Persistenz-Filter)

Meine Gefühl zeigt an, dass das Problem im Sitzungskontext liegt. Ich habe das Gefühl (aber ich kann es nicht wirklich begreifen), dass es meinen Persistenzkontext über mehrere Anfragen wiederverwendet.

Ich habe einige Frameworks zusammen, um das alles funktionieren zu lassen. Ich benutze Resteasy als Jax-Rs-Implementierer. guice (4.0beta4) als cdi implementor und Hibernate als jpa implementor. Da wir beim Einfügen des EntityManagers einen Provider verwenden müssen (da der EntityManager für jede Transaktion erstellt wird), habe ich dies in einen EntityManagerProxy gehüllt. Diese Klasse implementiert die EntityManager-Schnittstelle und delegiert alle Methoden an provider.get(). Method().

public class EntityManagerProxy implements EntityManager { 
    private final Provider<EntityManager> entityManagerProvider; 

    @Inject 
    public EntityManagerProxy(final Provider<EntityManager> entityManagerProvider) { 
     this.entityManagerProvider = entityManagerProvider; 
    } 

    private EntityManager getEntityManager() { 
     return entityManagerProvider.get(); 
    } 

    @Override 
    public void persist(final Object entity) { 
     getEntityManager().persist(entity); 
    } 
} 

Mein guice Modul sieht wie folgt aus

public class OptiWEEEModule extends ServletModule implements Module { 
    @Override 
    protected void configureServlets() { 

     super.configureServlets(); 
     bind(EntityManagerProxy.class); 
     // JPA 
     install(new JpaPersistModule("myPU")); 
    } 
} 

Ich weiß, dass dies eine vage Frage ist, könnte aber jemand mich in die richtige Richtung helfen? Dies ist nicht wirklich ein Problem, für das ich eine Fehlermeldung ausgeben kann.

edit: Ich habe jetzt Pin auf das Problem hingewiesen. Mit einem Profiler sah ich aus, als ob der Entity Context von Guice wiederverwendet wurde. Dies bedeutet, dass die Abfrage nicht immer ausgeführt wird, sondern der vorhandene Entitätsmanager verwendet wird, der jedes Mal erstellt werden soll, wenn eine @transactional Annotation übergeben wird.

+0

Ich habe gerade von guice 4beta4 zu guice 3 herabgestuft und der gleiche Fehler tritt auf. – jelle

+0

Die Idee von '@ Transactional', dass Sie eine neue Transaktion erhalten, nicht einen neuen EntityManager. Letzteres kann nur wenige davon gut bewältigen. Sie zeigen weder den "update" -Teil Ihres Proxys noch die Webservices, daher ist es schwer zu sagen, was Ihr Problem tatsächlich verursacht. – mabi

+0

Ich habe tatsächlich das Problem niedergebrannt. Nicht der Update-Teil bricht meine Anwendung, aber der Entitymanager wird in jedem Thread wiederverwendet. Ich denke, ich erstelle einen Singleton, der meinen Entitymanager enthält. Könnte mein EntityManagerProxy dies verursachen? Dies ist die Strategie, der ich folge https://code.google.com/p/google-guice/wiki/JPA#Session-per-transaction_strategy – jelle

Antwort

1

Ich habe diesen Awnser aus den Mailinglisten.

Guice Perstist hat eine Eigenschaft, die eher ungewöhnlich ist und einige Probleme verursacht. Ich denke, Sie könnten es nur schlagen

Wenn Sie einen Entity Manager außerhalb einer Arbeitseinheit anfordern, wird Guice persist implizit die Arbeitseinheit für Sie starten. Leider ist das isActive() auf UnitOfWork ist Paket privat. Und Sie können nicht testen, wenn eine Arbeitseinheit aktiv ist.

Es gibt zwei Möglichkeiten, eine Arbeitseinheit explizit zu starten und zu beenden. Sie können die UnitOfWork und die Methoden begin() und end() verwenden. Auch die @Transactional Annotation startet eine Arbeitseinheit. @Transactional wird auch die Arbeitseinheit beenden, wenn und nur wenn es gestartet wurde.

Es wird empfohlen, nur einen Entity Manager innerhalb einer @Transactional-Methode zu erhalten.

Ich kann nur schlussfolgern, dass die Annotation @Transaction nicht den gleichen Reifegrad wie der im Frühjahr hat.Wenn Sie andererseits den Entity Manager innerhalb eines @Transactional Managers über einen Provider bekommen, wird dieses Problem nicht wirklich gelöst.

Da wir sehr bald in die Produktion gehen, habe ich zurück ins Frühjahr gewechselt, was eine Schande ist, aber war die einzige vernünftige Lösung, um unsere Frist zu verwalten.