2014-05-06 29 views
6

Ho un'applicazione web con un comportamento strano in cui non riesco davvero a mettere il dito. Il nocciolo del mio problema è che esiste un comportamento incoerente nei valori restituiti dai miei endpoint di riposo. Quando avvio la mia applicazione, la mia query restituisce gli stessi valori ogni volta che chiamo questo endpoint. Quando aggiorno un'entità, il mio gestore di entità inizia a comportarsi in modo strano. Ora la mia query inizia a restituire risultati diversi. Una volta restituisce valori precedenti anziché i valori presenti nel database o l'elenco dei risultati contiene proxy anziché oggetti (misti). enter image description herejpa2 riutilizza entityManager con guice

ho convalidato che i miei metodi @transaction sono posizionati correttamente e nel mio stack di debug vedo l'intercettore transazione ed il gestore di entità viene creato per ogni richiesta al backend (quindi nessun filtro Guice persistenza)

mio sentimento indica che il problema sta nel contesto della sessione. Ho la sensazione (ma non riesco davvero a capirlo) che riutilizza il mio contesto di persistenza su più richieste.

Ho messo insieme alcuni framework per far funzionare tutto questo. Io uso resteasy come implementatore jax-rs. guice (4.0beta4) come cdi implementor e hibernate come jpa implementor. Poiché è necessario utilizzare un provider quando si inietta l'entitymanager (poiché il gestore entità viene creato ogni transazione), l'ho racchiuso in un EntityManagerProxy. Questa classe implementa l'interfaccia EntityManager e delega tutti i metodi a 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); 
    } 
} 

mio modulo Guice assomiglia a questo

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

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

So che questo è un problema vaga, ma qualcuno potrebbe aiutarmi nella giusta direzione? Questo non è davvero un problema per cui posso fornire un messaggio di errore.

modifica: ora ho sottolineato il problema. Con un profiler mi è sembrato che il contesto dell'entità sia riutilizzato per guing. Ciò significa che non esegue ogni volta la query, ma utilizza il gestore di entità esistente, che dovrebbe essere creato ogni volta che viene passata un'annotazione @ transazionale.

+0

Ho appena eseguito il downgrade da guce 4beta4 a guice 3 e si verifica lo stesso errore. – jelle

+0

L'idea di '@ Transactional' che si ottiene una nuova transazione, non un nuovo EntityManager. Quest'ultimo in grado di gestire alcuni di quelli altrettanto bene. Non mostri la parte "aggiornamento" del tuo proxy né i servizi web, quindi è difficile dire quale sia la causa del tuo problema. – mabi

+0

In realtà ho risolto il problema. Non la parte di aggiornamento interrompe la mia applicazione, ma il gestore di entità viene riutilizzato su ciascun thread. Credo di creare un singleton che detiene il mio gestore di entità. Il mio entitymanagerproxy potrebbe causare questo? questa è la strategia che sto seguendo https://code.google.com/p/google-guice/wiki/JPA#Session-per-transaction_strategy – jelle

risposta

1

Ho ricevuto questo proprietario dalle mailing list.

Guice perstist ha una funzionalità piuttosto insolita e causa alcuni problemi . Penso che potresti semplicemente colpirlo

Quando richiedi un gestore di entità al di fuori di un'unità di lavoro guaina persist, avvierà implicitamente l'unità di lavoro per te. Sfortunatamente isActive() su UnitOfWork è un pacchetto privato. E non è possibile testare se un'unità di lavoro è attiva.

Esistono due modi per avviare e terminare esplicitamente un'unità di lavoro. È possibile utilizzare UnitOfWork ei metodi begin() e end(). Anche l'annotazione @Transactional avvia un'unità di lavoro. @Transactional: termina anche l'unità di lavoro se e solo se è stata avviata.

È consigliabile ottenere un gestore di entità solo all'interno di un metodo @Transactional.

Posso solo concludere che l'annotazione @Transaction non è dello stesso livello di maturità di quello in primavera.D'altra parte ottenere il gestore di entità all'interno di un gestore @Transactional tramite un provider non risolve questo problema.

Dato che ci stiamo avvicinando alla produzione molto presto, sono tornato alla primavera, il che è un peccato, ma è stata l'unica soluzione ragionevole per gestire la nostra scadenza.

Problemi correlati