2009-08-21 18 views
64

Una lunga domanda, si prega di sopportare con me.Iniezione di EntityManager vs. EntityManagerFactory

Stiamo usando Primavera + APP per un'applicazione web. La mia squadra sta discutendo sull'iniezione di EntityManagerFactory nel GenericDAO (un DAO basato su Generics qualcosa sulle linee fornite da APPFUSE, non usiamo JpaDaosupport per qualche motivo) per l'iniezione di un EntityManager. Stiamo usando "application managed persistence".

Gli argomenti contro l'iniezione di un EntityManagerFactory sono troppo pesanti e quindi non necessari, lo EntityManager fa ciò di cui abbiamo bisogno. Inoltre, poiché Spring creerebbe una nuova istanza di un DAO per ogni richiesta Web (dubito di questo) non ci saranno problemi di concorrenza poiché nella stessa istanza EntityManager è condivisa da due thread.

L'argomentazione per l'iniezione di EFM è che è una buona pratica, nonostante sia sempre buona cosa avere una maniglia per una fabbrica.

Non sono sicuro quale sia l'approccio migliore, qualcuno può per favore illuminarmi?

+2

Capisco inoltre che quando Spring inietta EntityManager è "container managed persistence" e anche che Spring "rende" il thread Entitymanagers sicuro. SB –

risposta

49

I pro e i contro dell'iniezione di EntityManagerFactory vs EntityManager sono tutti espressi nei documenti Spring here, non sono sicuro di poterlo migliorare.

Detto questo, ci sono alcuni punti nella domanda che dovrebbero essere chiariti.

... Primavera creerebbe una nuova istanza di un DAO per ogni richiesta web ...

Questo non è corretto. Se il tuo DAO è un bean Spring, allora è un singleton, a meno che non lo configuri diversamente tramite l'attributo scope nella definizione bean. Istanziare un DAO per ogni richiesta sarebbe pazzesco.

L'argomento per l'iniezione di EMF è che la sua una buona pratica in tutto il suo sempre bene avere una maniglia per una fabbrica .

Questo argomento non regge molto. Le buone pratiche generali dicono che un oggetto dovrebbe essere iniettato con i collaboratori minimi di cui ha bisogno per svolgere il proprio lavoro.

6

Ho trovato che l'impostazione dell'annotazione @Repository Spring sui DAO e l'utilizzo di EntityManager gestito da Spring e immesso dall'annotazione @PersistenceContext è il modo più conveniente per far funzionare tutto correttamente. Beneficiate della sicurezza del thread dell'EntityManager condiviso e della traduzione delle eccezioni. Per impostazione predefinita, EntityManager condiviso gestirà le transazioni se si combinano diversi DAO da un gestore, ad esempio. Alla fine scoprirai che i tuoi DAO diventeranno anemici.

23

Sto mettendo giù ciò che ho finalmente raccolto. Dalla sezione "Implementing DAOs based on plain JPA" nella primavera Riferimento:

Anche se casi EntityManagerFactory sono thread-safe, EntityManager casi non lo sono. L'EntityManager JPA iniettato si comporta come un EntityManager prelevato dall'ambiente JNDI di un server delle applicazioni, come definito dalla specifica JPA.Delega tutte le chiamate allo EntityManager transazionale corrente , se presente; in caso contrario, torna a a un EntityManager appena creato per operazione, rendendo in effetti il ​​thread di utilizzo .

Ciò significa che, secondo le specifiche JPA, le istanze EntityManager non sono thread-safe, ma se Spring le gestisce, sono rese thread-safe.

Se si utilizza Spring, è meglio iniettare EntityManagers anziché EntityManagerFactory.

9

Penso che questo sia già stato ben coperto, ma solo per rafforzare alcuni punti.

  • Il DAO, se iniettato da Spring, è un singoletto per default. È necessario impostare esplicitamente l'ambito sul prototipo per creare una nuova istanza ogni volta.

  • La mangiatoia entità iniettato da @PersistenceContext è sicuro thread.

Detto questo, ho avuto alcuni problemi con un DAO singleton nella mia applicazione multi-thread. Ho finito per fare del DAO un fagiolo istanziato e questo ha risolto il problema. Quindi, anche se la documentazione potrebbe dire una cosa, probabilmente vorrete testare accuratamente la vostra applicazione.

Follow-up:

Credo che parte del mio problema è che io sto usando

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

Se si utilizza PersistenceContextType.EXTENDED, tenere a mente che devi, se ho capito bene, chiudere manualmente la transazione. Vedere il thread this per ulteriori informazioni.

Un'altra Follow-up:

Utilizzando un DAO istanziato è una pessima idea. Ogni istanza del DAO avrà la propria cache di persistenza e le modifiche a una cache non verranno riconosciute da altri bean DAO. Mi dispiace per il cattivo consiglio.

Problemi correlati