2009-08-21 18 views
64

Una larga pregunta, por favor tengan paciencia conmigo.Inyectando EntityManager vs. EntityManagerFactory

Estamos utilizando Spring + JPA para una aplicación web. Mi equipo está debatiendo sobre inyectar EntityManagerFactory en el GenericDAO (un DAO basado en Generics algo en las líneas proporcionadas por APPFUSE, no usamos JpaDaosupport por algún motivo) sobre la inyección de un EntityManager. Estamos usando "persistencia administrada por la aplicación".

Los argumentos en contra de la inyección de un EntityManagerFactory es que es demasiado pesado y por lo tanto no se requiere, la EntityManager hace lo que necesitamos. Además, como Spring crearía una nueva instancia de un DAO para cada solicitud web (lo dudo) no habrá problemas de concurrencia ya que en la misma instancia EntityManager se comparten dos subprocesos.

El argumento para inyectar EFM es que es una buena práctica sobre todo siempre es bueno tener un control para una fábrica.

No estoy seguro de cuál es el mejor enfoque, ¿alguien puede por favor aclararme?

+2

Entiendo además que cuando Spring inyecta el EntityManager es "persistencia gestionada por contenedor" y también que Spring "hace" que el subproceso de Entitymanagers sea seguro. SB –

Respuesta

49

Los pros y los contras de inyectar EntityManagerFactory vs EntityManager están detallados en los documentos de Spring here, no estoy seguro si puedo mejorar eso.

Diciendo eso, hay algunos puntos en su pregunta que deben aclararse.

... Spring crearía una nueva instancia de un DAO para cada solicitud Web ...

Esto no es correcto. Si su DAO es un bean de Spring, entonces es un singleton, a menos que lo configure de otra manera a través del atributo scope en la definición de bean. Instanciar un DAO para cada solicitud sería una locura.

El argumento para la inyección de EMF es que es una buena práctica durante toda su siempre es bueno tener un identificador para una fábrica .

Este argumento realmente no se sostiene. La buena práctica general dice que un objeto debe ser inyectado con los colaboradores mínimos que necesita para hacer su trabajo.

6

Encontré que establecer la anotación @Repository Spring en nuestros DAO y tener EntityManager administrado por Spring e inyectado por la anotación @PersistenceContext es la forma más conveniente de hacer que todo funcione con fluidez. Se beneficia de la seguridad de subprocesos del EntityManager compartido y la traducción de excepciones. De forma predeterminada, el EntityManager compartido administrará las transacciones si combina varios DAO de un administrador, por ejemplo. Al final, descubrirá que sus DAO se volverán anémicos.

23

Estoy escribiendo lo que finalmente he reunido. Desde la sección "Implementing DAOs based on plain JPA" en la Referencia de primavera:

Aunque casos EntityManagerFactory son thread-safe, EntityManager casos no lo son. El JPA EntityManager inyectado se comporta como un EntityManager recuperado del entorno JNDI de un servidor de aplicaciones, tal como lo define la especificación JPA.Delega todas las llamadas al EntityManager transaccional actual, si existe; de lo contrario, retrocede a un EntityManager de nueva creación por operación, lo que hace que el uso de sea seguro para subprocesos.

Esto significa que según las especificaciones de la APP EntityManager casos no es seguro para subprocesos, pero si la primavera se ocupa de ellos, que están hechas de hilo de seguridad.

Si está utilizando Spring, es mejor inyectar EntityManagers en lugar de EntityManagerFactory.

9

Creo que esto ya ha sido bien cubierto, pero solo para reforzar algunos puntos.

  • La DAO, si se inyecta por Spring, es un singleton por defecto. Tienes que establecer explícitamente el alcance al prototipo para crear una nueva instancia cada vez.

  • El pesebre entidad inyectado por @PersistenceContext es seguro para subprocesos.

Dicho esto, yo tenía algunos problemas con un producto único DAO en mi aplicación multi-hilo. Terminé haciendo del DAO un bean instanciado y eso resolvió el problema. Entonces, aunque la documentación puede decir una cosa, es probable que desee probar su aplicación a fondo.

Seguimiento:

Creo que parte de mi problema es que estoy usando

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

Si utiliza PersistenceContextType.EXTENDED, tenga en cuenta que usted tiene que, si he entendido bien, cerrar manualmente la transacción. Consulte el hilo this para obtener más información.

Otro Seguimiento:

El uso de un DAO de instancia es una muy mala idea. Cada instancia del DAO tendrá su propio caché de persistencia y los cambios a un caché no serán reconocidos por otros beans DAO. Perdón por el mal consejo.

Cuestiones relacionadas