13 votes

JPA/EclipseLink : EntityManager.getTransaction() crée-t-il une nouvelle transaction ou retourne-t-il la transaction active ?

J'utilise EclipseLink 2.3.0. J'ai une méthode que j'appelle depuis un test unitaire (donc en dehors d'un conteneur, pas de JTA) qui ressemble à ceci :

EntityManager em = /* get an entity manager */;
em.getTransaction().begin();
// make some changes
em.getTransaction().commit();

Les changements n'étaient PAS persistés dans la base de données, j'ai regardé cela pendant longtemps et j'ai finalement réalisé que EntityManager.getTransaction() retournait en fait une NOUVELLE EntityTransaction, au lieu de la même dans les deux appels. L'effet est que le premier appel crée une nouvelle transaction et la démarre, et que le second appel crée une AUTRE transaction et la valide. Comme la première transaction n'a jamais été validée, les modifications ne sont pas sauvegardées. Nous avons vérifié cela de la manière suivante :

log.info(em.getTransaction().toString());
log.info(em.getTransaction().toString());

Ce qui a donné lieu aux messages suivants :

INFO: org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl@1e34f445
INFO: org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl@706a4d1a

Les deux ID d'objets différents permettent de vérifier qu'il existe deux instances différentes. Modifier le code comme suit :

EntityManager em = /* get an entity manager */;
EntityTransaction tx = em.getTransaction();
tx.begin();
// make some changes
tx.commit();

... a remédié au problème. Maintenant, lorsque j'exécute le code, je vois les instructions SQL générées pour effectuer le travail sur la base de données, et en regardant dans la base de données, les données ont été modifiées.

J'ai été un peu surpris par ce résultat, car j'ai vu de nombreux exemples de code en ligne (pour JPA en général et pour EclipseLink en particulier) qui recommandent le code que nous avons utilisé pour gérer les transactions. J'ai cherché très loin des informations spécifiques à ce sujet, mais je n'ai rien trouvé. Que se passe-t-il donc ?

J'ai cherché dans les spécifications JPA quelque chose qui spécifie exactement ce que fait getTransaction() et ce n'était pas spécifique si la transaction est nouvelle ou identique. Existe-t-il un paramètre dans persistence.xml qui contrôle cela ? Le comportement est-il spécifique à chaque implémentation de la spécification JPA ?

Merci beaucoup pour toute information ou conseil.

5voto

James Points 18355

L'utilisation de getTransaction() fonctionne dans JPA et dans EclipseLink (c'est ainsi que fonctionnent nos propres tests).

Je pense que vous faites quelque chose d'autre de très étrange.

Utilisez-vous Spring ou une autre couche ? Veuillez inclure l'ensemble du code et le fichier persistence.xml de votre test. Assurez-vous que vous n'utilisez pas JTA dans votre persistence.xml.

1voto

JB Nizet Points 250258

La spécification JPA (voir paragraphe 7.5.4) contient des exemples explicites montrant l'utilisation de la fonction getTransaction() pour commencer et valider la transaction. Votre code devrait donc être correct.

Votre test montre que vous obtenez deux objets différents, mais cela ne signifie pas que la même transaction n'est pas utilisée. Peut-être que l'objet retourné n'est qu'un proxy d'un seul et véritable objet de transaction.

Il se peut aussi que la transaction soit validée ou annulée à l'intérieur du code caché sous la rubrique // make some changes .

0voto

Azimuts Points 602

Avez-vous essayé d'utiliser persister avant la validation : ?

  Employee employee = new Employee("Samuel", "Joseph", "Wurzelbacher");
  em.getTransaction().begin();
  em.persist(employee);
  em.getTransaction().commit();

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X