web-dev-qa-db-fra.com

JAVA: un objet EntityManager dans un environnement multithread

si j'ai plusieurs threads, chacun utilise l'injecteur pour obtenir l'objet EntityManager, chacun utilise l'objet em pour sélectionner une liste d'autres objets de classe. Prêt à être utilisé dans une boucle for.

Si un thread termine en premier et appelle clear (), cela affectera-t-il les autres threads? Comme la boucle for aura une exception?

Que diriez-vous de fermer ()?

Si la réponse est "Cela dépend", qu'est-ce que (définition de classe? Appel de méthode?) Et où (code Java? Annotation? Xml?) Dois-je regarder pour savoir comment cela dépend?

Je n'ai pas écrit la source, j'utilise simplement la bibliothèque de quelqu'un d'autre sans documentation.

Je vous remercie.

22
user1589188

Voici le thread-safe Entity Manager Helper complet.

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class EntityManagerHelper {

    private static final EntityManagerFactory emf;
    private static final ThreadLocal<EntityManager> threadLocal;

    static {
        emf = Persistence.createEntityManagerFactory("Persistent_Name");
        threadLocal = new ThreadLocal<EntityManager>();
    }

    public static EntityManager getEntityManager() {
        EntityManager em = threadLocal.get();

        if (em == null) {
            em = emf.createEntityManager();
            // set your flush mode here
            threadLocal.set(em);
        }
        return em;
    }

    public static void closeEntityManager() {
        EntityManager em = threadLocal.get();
        if (em != null) {
            em.close();
            threadLocal.set(null);
        }
    }

    public static void closeEntityManagerFactory() {
        emf.close();
    }

    public static void beginTransaction() {
        getEntityManager().getTransaction().begin();
    }

    public static void rollback() {
        getEntityManager().getTransaction().rollback();
    }

    public static void commit() {
        getEntityManager().getTransaction().commit();
    }
}
29
Makky

Les gestionnaires d'entités ne sont pas sécurisés pour les threads (source tutoriel Java EE 6 ) et ne peuvent pas être partagés entre les threads. Chaque thread doit utiliser son propre gestionnaire d'entités, sans quoi des incidents graves se produiront, quels que soient les appels clear() ou close().

Mais, si l'injecteur injecte chaque thread avec son propre gestionnaire d'entités, tout devrait bien se passer.

Spring et éventuellement d'autres infrastructures DI injecteront un proxy basé sur ThreadLocal pour un véritable gestionnaire d'entités dans vos beans. Les appels passés par chaque thread adresseront un proxy à la véritable instance locale d'un thread d'un gestionnaire d'entités: c'est ainsi que les choses peuvent fonctionner même s'il peut sembler qu'un gestionnaire d'entités soit partagé entre plusieurs threads.

Plus de détails sur la manière dont votre responsable d'entité est injecté seraient utiles (Spring, etc.)

12
prunge

Il existe deux types de gestionnaires EntityManager: les conteneurs gérés et les applications gérées. Pour les applications gérées, la méthode préférée pour obtenir EntityManager consiste à utiliser EntityManagerFactory. Le tutoriel Java EE dit ceci:

Gestionnaires d'entités gérées par conteneur 

Avec une entité gérée par conteneur gestionnaire, le contexte de persistance d’une instance EntityManager est propagé automatiquement par le conteneur à toutes les applications composants qui utilisent l'instance EntityManager dans un seul fichier Java Transaction API (JTA).

Les transactions JTA impliquent généralement des appels entre les composants de l'application . Pour compléter une transaction JTA, ces composants doivent généralement avoir accès à un seul contexte de persistance. Cela se produit lorsqu'un EntityManager est injecté dans les composants de l'application à l'aide du fichier javax.persistence.PersistenceContext annotation. La persistance le contexte est automatiquement propagé avec la transaction JTA en cours, et les références EntityManager mappées sur la même persistance l’unité donne accès au contexte de persistance dans cette transaction. En propageant automatiquement le contexte de persistance, les composants de l’application n’ont pas besoin de passer des références à EntityManager instances entre elles afin d’apporter des modifications au sein d’une seule transaction. Le conteneur Java EE gère le cycle de vie de gestionnaires d'entités gérées par conteneur.

Pour obtenir une instance de EntityManager, injectez le gestionnaire d'entités dans le composant d'application:

@PersistenceContext 
EntityManager em; 

Gestionnaires d'entités gérées par l'application 

Avec un gestionnaire d'entités gérées par l'application, de l'autre Par contre, le contexte de persistance n'est pas propagé à l'application composants, et le cycle de vie des instances EntityManager est géré par L'application.

Les gestionnaires d'entités gérées par les applications sont utilisés lorsque les applications ont besoin de accéder à un contexte de persistance qui n'est pas propagé avec le JTA transaction entre instances de EntityManager dans une persistance particulière unité. Dans ce cas, chaque EntityManager crée un nouveau fichier .__ isolé. contexte de persistance. EntityManager et sa persistance associée les contextes sont créés et détruits explicitement par l'application. Ils sont également utilisés lorsqu’une injection directe d’instances EntityManager ne peut pas être done car les instances de EntityManager ne sont pas thread-safe . Les instances EntityManagerFactory sont thread-safe.

http://docs.Oracle.com/javaee/6/tutorial/doc/bnbqw.html

4
gerrytan

Vous avez normalement des transactions autour de ce que vous faites avec des objets de base de données. Ce que chaque thread donné voit au sujet des modifications apportées par d'autres threads est contrôlé par les paramètres d'isolation de transaction.

Commencez à vous renseigner sur différents paramètres d'isolation et appliquez le bon paramètre en fonction de vos besoins. Il existe un compromis entre précision et rapidité . http://fr.wikipedia.org/wiki/Isolation_%28database_systems%29

1
n0rm1e

Cela fait environ trois ans :), mais pour ce qui est d'injecter EntityManager dans les EJB, voici un lien vers l'entrée de blog d'Adam Bien http://www.adam-bien.com/roller/abien/entry/is_in_an_ejb_injected

copier-coller à partir de là:

"Vous pouvez injecter EntityManager directement dans les EJB. Mais: est-ce thread-safe ?:

@Stateless
public class BookServiceBean implements BookService {


  @PersistenceContext EntityManager em;

  public void create(Book book) { this.em.persist(book);}

 }

"

et la réponse est, encore une fois copier-coller:

"Travailler avec des EJB sans configuration supplémentaire est thread-safe, que vous appeliez une ou plusieurs méthodes simultanément. Le conteneur se soucie de la sérialisation des appels.",

cela pourrait peut-être être plus clair, mais cela implique que vous puissiez injecter EntityManager dans des beans de session sans état, sans vous soucier des problèmes de simultanéité EntityManager.

0
John Donn