qualifier español dependent beans java java-ee-6 cdi

español - Java CDI @PersistenceContext y seguridad de subprocesos



cdi scopes (3)

Aunque las implementaciones de EntityManager no son seguras para subprocesos, el contenedor Java EE inyecta un proxy que delega todas las invocaciones de métodos a un EntityManager vinculado a la transacción. Por lo tanto, cada transacción funciona con su propia instancia de EntityManager . Esto es cierto para al menos el contexto de persistencia de ámbito de transacción (que es el predeterminado).

Si el contenedor inyectara una nueva instancia de EntityManager en cada bean, el siguiente no funcionaría:

@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 call ocurre en una sola transacción y, por lo tanto, los beans deben compartir el mismo EntityManager . En realidad, comparten el mismo EntityManager proxy que delega las llamadas al mismo contexto de persistencia.

Por lo tanto, es legal usar EntityManager en beans singleton como a continuación:

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

Otra prueba es que no hay ninguna mención de seguridad de subprocesos en EntityManager javadoc. Así que mientras permanezca dentro del contenedor Java EE , no debería preocuparse por el acceso de concurrencia a EntityManager .

¿Es un EntityManager @Inject [ed] como sigue en varias clases threadsafe?

@PersistenceContext(unitName="blah") private EntityManager em;

This pregunta y esta parecen ser específicas para la primavera. Estoy usando los servicios de Jave EE CDI


Para mi gran sorpresa (después de años de usar jpa en spring ) EntityManager no es seguro para subprocesos . Esto es realmente comprensible si lo piensa más a fondo: EntityManager es solo un envoltorio alrededor de la implementación JPA nativa, por ejemplo, sesión en Hibernate, que a su vez es un envoltorio alrededor de la conexión jdbc . Dicho esto, EntityManager no puede ser seguro para subprocesos ya que representa una conexión / transacción de base de datos.

Entonces, ¿por qué funciona en primavera? Debido a que envuelve el EntityManager destino en un proxy, en principio utiliza ThreadLocal para mantener la referencia local para cada hilo. Esto es necesario ya que las aplicaciones Spring se crean sobre singletons mientras que EJB usa el grupo de objetos.

¿Y cómo puedes lidiar con eso en tu caso? No sé cdi pero en EJB se agrupan cada bean de sesión sin estado y con estado, lo que significa que realmente no se puede llamar al método del mismo EJB desde varios subprocesos al mismo tiempo. Por EntityManager tanto, EntityManager nunca se utiliza simultáneamente. Dicho esto, inyectar EntityManager es seguro , al menos en beans de sesión sin estado y con estado.

Sin embargo, inyectar EntityManager a servlets y singleton beans no es seguro ya que posiblemente varios subprocesos pueden acceder a ellos al mismo tiempo, desordenando con la misma conexión JDBC.

Ver también


Siento que necesito profundizar más en esto porque mi primera respuesta no fue del todo cierta.

Me referiré a JSR-220 . En la sección 5.2 Obteniendo un EntityManager puedes encontrar:

Un administrador de entidades no se puede compartir entre varios subprocesos que se ejecutan simultáneamente. Solo se puede acceder a los administradores de entidades de una sola manera.

Bueno, eso es todo. Puede dejar de leer aquí y nunca usar EntityManager en beans singleton a menos que esté sincronizado correctamente.

Pero creo que hay una confusión en la especificación. En realidad, hay dos implementaciones diferentes de EntityManager . El primero es uno es la implementación del proveedor (que dice Hibernate) que no está obligada a ser segura para subprocesos.

Por otro lado hay una implementación de contenedor de EntityManager . Lo que tampoco se supone que sea seguro para subprocesos de acuerdo con lo anterior. Pero la implementación del contenedor actúa como un proxy y delega todas las llamadas al EntityManager del proveedor real.

Así que más adelante en la especificación de 5.9 Contratos de tiempo de ejecución entre el contenedor y el proveedor de persistencia :

Para la administración de un contexto de persistencia de ámbito de transacción, si no hay un EntityManager ya asociado con la transacción JTA: El contenedor crea un nuevo administrador de entidades llamando a EntityManagerFactory.createEntityManager cuando ocurre la primera invocación de un administrador de entidades con Persistence- ContextType.TRANSACTION dentro del alcance de un método de negocio que se ejecuta en la transacción JTA.

Esto significa, a su vez, que habrá una instancia diferente de EntityManager para cada transacción iniciada. El código que crea un EntityManager es seguro de acuerdo con 5.3 :

Los métodos de la interfaz EntityManagerFactory son seguros para subprocesos.

¿Pero qué pasa si hay un EntityManager asociado con la transacción JTA? El código que vincula un EntityManager asociado con la transacción JTA actual puede no ser seguro para subprocesos según la especificación.

Pero realmente no puedo pensar en una implementación de servidor de aplicaciones que funcione correctamente con EntityManager inyectado en beans sin estado y no correctamente dentro de singletons.

Así que mis conclusiones son:

  1. Si desea seguir el JSR-220 estrictamente, nunca use EntityManager en singletons hasta que sincronice el acceso a él.
  2. Personalmente, continuaré utilizando EntityManager en singleton porque la implementación de mi servidor de aplicaciones funciona perfectamente con él. Es posible que desee comprobar su implementación antes de hacerlo.