Une longue question, s’il vous plaît, supportez-moi.
Nous utilisons Spring + JPA pour une application Web. Mon équipe discute de l’injection de EntityManagerFactory
dans GenericDAO
(un DAO basé sur quelque chose de générique sur les lignes fournies par APPFUSE, nous n’utilisons pas JpaDaosupport
pour une raison quelconque) en injectant un EntityManager
. Nous utilisons “persistence gérée par application”.
Les arguments contre l’injection d’un EntityManagerFactory
est que c’est trop lourd et n’est donc pas nécessaire, EntityManager
fait ce dont nous avons besoin. De plus, comme Spring créerait une nouvelle instance de DAO pour chaque requête Web (cela ne fait aucun doute), il n’y aura pas de problèmes de concurrence, car la même instance EntityManager
est partagée par deux threads.
L’argument en faveur de l’injection d’EFM est que c’est une bonne pratique dans tous les cas, il est toujours bon d’avoir une poignée d’usine.
Je ne suis pas sûr quelle est la meilleure approche, quelqu’un peut-il m’éclairer s’il vous plaît?
Les avantages et les inconvénients d’injecter EntityManagerFactory vs EntityManager sont tous expliqués dans les docs Spring ici , je ne suis pas sûr de pouvoir améliorer cela.
En disant cela, certains points de votre question doivent être clarifiés.
… Spring créerait une nouvelle instance de DAO pour chaque requête Web …
Ce n’est pas correct Si votre DAO est un bean Spring, alors c’est un singleton, sauf si vous le configurez autrement via l’atsortingbut scope
dans la définition du bean. L’instanciation d’un DAO pour chaque demande serait folle.
L’argument en faveur de l’injection de CEM est que c’est une bonne pratique, il est toujours bon d’avoir une poignée d’usine.
Cet argument ne retient pas vraiment l’eau. Selon les bonnes pratiques générales, un object doit être injecté avec le minimum de collaborateurs dont il a besoin pour faire son travail.
Je dépose ce que j’ai finalement rassemblé. Dans la section ” Implémentation de DAO basés sur JPA ordinaire ” dans la référence Spring:
Bien que les instances EntityManagerFactory soient sûres pour les threads, les instances EntityManager ne le sont pas. Le JPA EntityManager injecté se comporte comme un EntityManager extrait de l’environnement JNDI d’un serveur d’applications, tel que défini par la spécification JPA. Il délègue tous les appels au EntityManager transactionnel actuel, le cas échéant; sinon, il revient à une EntityManager nouvellement créée par opération, ce qui rend son utilisation sûre pour les threads.
Cela signifie que, selon les spécifications JPA, les instances EntityManager ne sont pas thread-safe, mais si Spring les gère, elles sont sécurisées pour les threads.
Si vous utilisez Spring, il est préférable d’injecter EntityManagers au lieu d’EntityManagerFactory.
Je pense que cela a déjà été bien couvert, mais juste pour renforcer quelques points.
Le DAO, s’il est injecté par Spring, est un singleton par défaut . Vous devez définir explicitement la scope sur prototype pour créer une nouvelle instance à chaque fois.
Le gestionnaire d’entités injecté par @PersistenceContext est thread-safe .
Cela étant dit, j’ai eu quelques problèmes avec un DAO singleton dans mon application multi-thread. J’ai fini par faire du DAO un haricot instancié et cela a résolu le problème. Donc, bien que la documentation puisse dire une chose, vous voudrez probablement tester votre application en profondeur.
Suivre:
Je pense qu’une partie de mon problème est que j’utilise
@PersistenceContext(unitName = "unit", type = PersistenceContextType.EXTENDED)
Si vous utilisez PersistenceContextType.EXTENDED, gardez à l’esprit que vous devez, si je comprends bien, fermer manuellement la transaction. Voir ce fil pour plus d’informations.
Un autre suivi:
L’utilisation d’un DAO instancié est une très mauvaise idée. Chaque instance du DAO aura son propre cache de persistance et les modifications apscopes à un cache ne seront pas reconnues par les autres beans DAO. Désolé pour le mauvais conseil.
J’ai trouvé que définir l’annotation @Repository Spring sur nos DAO et avoir EntityManager géré par Spring et injecté par l’annotation @PersistenceContext est le moyen le plus pratique pour que tout fonctionne correctement. Vous bénéficiez de la sécurité des threads du EntityManager partagé et de la traduction des exceptions. Par défaut, le EntityManager partagé gérera les transactions si vous combinez plusieurs DAO d’un gestionnaire par exemple. En fin de compte, vous constaterez que vos DAO deviendront anémiques.