Java CDI @PersistenceContext et la sécurité des threads

Est un EntityManager @Inject[ed] comme suit dans de multiples classes de thread-safe?

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

Ce question de et celui-ci semble être le Printemps spécifiques. Je suis à l'aide de Java EE CDI les services

20
demandé sur Community 2012-06-16 16:47:21

3 réponses

bien que EntityManager les implémentations elles-mêmes ne sont pas sans fil le Java EE conteneur injecte un proxy qui délègue toutes les invocations de méthodes à une transaction liée EntityManager . Par conséquent, chaque transaction fonctionne avec son propre EntityManager instance. Cela est vrai pour au moins le contexte de persistance à portée de transaction (qui est par défaut).

si conteneur injecterait une nouvelle instance de EntityManager dans chaque haricot le ci-dessous ne fonctionnerait pas:

@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 l'appel se produit dans une seule transaction et donc les haricots doivent partager le même EntityManager . En fait, ils partagent le même proxy EntityManager qui délègue les appels au même contexte de persistance.

Donc, vous êtes à l'utilisation légale EntityManager singleton haricots comme ci-dessous:

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

une autre preuve est qu'il n'y a aucune mention de la sécurité du fil dans EntityManager javadoc. Donc, pendant que vous restez à l'intérieur Java EE conteneur vous ne devriez pas vous soucier de l'accès simultané à EntityManager .

11
répondu polbotinka 2012-11-28 14:40:08

À ma grande surprise (après des années d'utilisation de dans ) EntityManager n'est pas thread-safe . C'est en fait compréhensible si vous y réfléchissez plus profondément: EntityManager est juste un enveloppeur autour de l'implémentation JPA native, par exemple session en hibernation, qui à son tour est un enveloppeur autour de . Cela étant dit EntityManager ne peut pas être thread safe car il représente un connexion à la base de données/transaction.

alors pourquoi ça marche au printemps? Parce qu'il enveloppe la cible EntityManager dans un proxy, en principe en utilisant ThreadLocal pour garder la référence locale par chaque thread. Cela est nécessaire car les applications de ressorts sont construites sur des singletons tandis que EJB utilise le pool d'objets.

Et comment pouvez-vous gérer cela dans votre cas? Je ne sais pas mais dans EJB chaque session apatride et stateful bean est mis en commun, ce qui signifie que vous ne pouvez pas vraiment appeler la méthode de la même EJB à partir de plusieurs threads dans le même temps. Ainsi, EntityManager n'est jamais utilisé concurremment. Cela étant dit, injection EntityManager est sûr , au moins dans les haricots de session apatrides et stateful.

Toutefois injection EntityManager à servlets et singleton haricots n'est pas sûr comme peut-être plusieurs threads peuvent accéder en même temps, de jouer avec le même JDBC connexion.

Voir aussi

16
répondu Tomasz Nurkiewicz 2012-12-17 08:57:25

je sens que je dois aller plus loin dans ce parce que ma première réponse n'était pas absolument vrai.

je vais me référer à JSR-220 . Dans la section 5.2 obtenir une EntityManager vous pouvez trouver:

un gestionnaire d'entité ne peut être partagé entre plusieurs entités simultanément. l'exécution de threads. Les gestionnaires d'entités ne peuvent être consultés que dans un single-threaded.

Eh bien c'est tout. Vous pouvez arrêter de lire ici et ne jamais utiliser EntityManager dans les haricots singleton à moins que correctement synchronisé.

mais je crois qu'il y a une confusion dans la spécification. Il existe en fait deux implémentations différentes EntityManager . Le premier est la mise en œuvre du fournisseur (dit Hibernate) qui n'est pas obligé d'être threadsafe.

d'autre part, il ya une mise en œuvre de conteneurs de EntityManager . Qui n'est pas non plus censé être threadsafe selon ce qui précède. Mais l'implémentation de container agit comme un proxy et délègue tous les appels au fournisseur réel EntityManager .

plus de dans le de spec dans 5.9 Exécution des Contrats entre le Conteneur et la Persistance Fournisseur :

Pour la gestion d'une transaction dans l'étendue du contexte de persistance, si il n'y a pas D'EntityManager déjà associé à la transaction JTA: Le conteneur crée un nouveau gestionnaire d'entité en appelant EntityManagerFactory.createEntityManager lors de la première invocation de un gestionnaire d'entité avec persistance-ContextType.La TRANSACTION se produit dans le cadre d'une méthode d'affaires exécutée dans la JTA transaction.

cela signifie à son tour qu'il y aura une instance différente EntityManager pour chaque la transaction a commencé. Le code qui crée un EntityManager est sûr selon 5.3 :

méthodes de L'EntityManagerFactory interface sont threadsafe.

mais qu'arrive-t-il s'il y a un EntityManager associé à la transaction JTA? Le code qui lie un EntityManager associé à la transaction courante de JTA peut ne pas être des threads selon la spécification.

mais je ne peux pas vraiment penser à une implémentation de serveur d'application qui fonctionne correctement avec EntityManager injecté dans des haricots apatrides et pas correctement dans des singletons.

donc mes conclusions sont:

  1. Si vous voulez suivre le JSR-220 strictement puis ne jamais utiliser de EntityManager dans les singletons jusqu' la synchronisation de l'accès.
  2. personnellement, je vais continuer à utiliser EntityManager dans singleton parce que l'implémentation de mon serveur d'application fonctionne parfaitement avec elle. Vous voudrez peut-être vérifier votre mise en œuvre avant de le faire.
8
répondu polbotinka 2013-01-02 11:44:57