IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JPA Java Discussion :

Fonctionnement des transactions avec JPA / JTA


Sujet :

JPA Java

  1. #1
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut Fonctionnement des transactions avec JPA / JTA
    Bonjour,

    je migre un vieux truc vers des choses un peux plus Java EE comme nottement jpa.

    C'est à la a base une application de type JSF 1.2 avec du hibernate derrière.

    La pratique, jusque là, c'etait le principe de une session hibernate par requetes, avec un système type detach / merge pour garder certains bean hibernate en session.

    J'ai migré le gros sous JPA, mais je me pose des questions sur les transaction. Avec hibernate je gérait ça à la main: si un action demandait un commit, on le faisait puis on continuait. Le servlet filter à la fin faisait son rollback si il n'y avait pas eu de commit.


    Aujourd'gui, avec JPA j'ai la session suivante:

    Des beans JSF @requestScoped
    Des beans "service" @requestscoped et ayant une injection d'un entitymanager
    JSF, via les bean, fait des requetes sur la base de données (get), inject les valeur recue de la requêtes (apply request value) et appelle des actions.

    Comment je dois gérer les transaction? Sachant que certaines action doivent impliquer de commiter les changements dans les beans, alors que d'autres ne doivent surtout pas permettre le commit. MAIS que les changement ont eu lieu en dehors de l'appel de l'action. Exemple:

    bouton "save" -> action "save" -> commit (comment le faire?)
    bouton "validate" -> action "validate" -> interdire le commit.

    donc comment gérer ces transaction? Je suis un peu perdu, j'ai bien peur qu'avec JTA le commit soit automatique

  2. #2
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 957
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 957
    Points : 4 386
    Points
    4 386
    Par défaut
    Séparez correctement les niveaux Service (@Secured) et Repository (@Transactional)
    Pour les fonctionnalités ne devant pas faire de commit, sortir du niveau Repository par une Exception spécifique à votre application (@Transactional avec rollbackFor …) que vous filtrez dans votre Service pour qu'elle ne "pollue" pas l'UI

  3. #3
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    ce que j'ai du mal à voir c'est comment ça s'intègre avec JSF.

    Le bean exposé par JSF est un bean JPA, donc lors du apply request value, JSF appelle les setteurs sur le bean géré par JPA donc

    1) il faut que JPA aie été chercher ce bean depuis la base de donnée dans une transaction
    2) il faut que cette transaction continue

    => comment dire au système qu"il faut une transaction à ce niveau? Je vais quand même pas mettre un @transactional sur chaque méthode de chaque bean JPA...


    Ensuite, viens l'action.

    Certaines actions entrainent un rollback => facile il suffit que j'appelle une méthode en @Transactional qui lance un exception ou fasse un setRollBackOnly sur le userTransaction
    D'autres entrainent un commit => je fais quoi, je fais un commit sur le userTransaction moi même?
    Enfin, si JSF commet un erreur (par exemple une erreur de validation), on ne passe jamais par mon code (car l'action n'est pas appelée) => Comment je dit à JPA que dans ce cas là il ne faut pas faire un commit?

    En gros, est-ce qu'on peux dire à JTA/JPA : pas de commit sauf si je t'y autorise explicitement? Parce que c'est sur ce principe que l'application était designée dans le passé et donc le plus simple pour moi à mettre en place.

    PS: je ne trouve pas de @Secured dans le javaEE 7

  4. #4
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Tu devrais regarder de ce côté
    Using @Resource for Transactions

    The @Resource annotation can be used to inject a
    UserTransaction into a component that is managing the
    transactions on its own. The
    javax.transaction.UserTransaction is an interface to
    the underlying JTA transaction manager. After obtaining a reference
    to the UserTransaction resource, a component can
    invoke the begin, commit, and
    rollback methods on the UserTransaction
    object to mark the boundaries of the transaction.

    .........
    @Resource
    UserTransaction utx;
    .........
    try {
    utx.begin();
    .........
    utx.commit();
    } catch(Exception err) {
    .........
    utx.rollback();
    .........
    }
    .........

  5. #5
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    oui, j'avais déjà vu cette option. Ce que je cherche surtout à savoir c'est quelles sont les recommendation. Car, arrete moi si je me trompe mais, à moins que je face explicitement un rollback (via la user transaction ou via une exception et un @Transactional par exemple, JTA va d'office commiter la transaction.

    Hors, si on a une erreur de validation jsf, à aucun moment, il n'y aura de rollback, et j'ai peur de me retrouver dans une situation où jpa fasse donc un commit en base des beans modifié alors qu'ils ne sont pas valides.

  6. #6
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Si tu lances une exception, il n'y aura pas de commit, le rollback est automatique

    [EDIT]
    Si l'exception est lancée au niveau de la couche EJB par la méthode de validation...
    dans ce que tu expliques (et je n'avais pas fait attention) tu aurais la possibilité d'appeler la couche de validation avec des erreurs au niveau JSF ?
    Normalement, la phase update model n'est pas appelé dans ce cas... ou alors tu voulais appeler la méthode de l'EJB dans la phase validation ?
    [/EDIT]

  7. #7
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    non c'est un peu plus compliqué


    comme je l'ai dit, les beans restent en session. Donc on peut très bien avoir cette situation:


    requete 1:
    -bean réattaché au contexte (je peux faire ça dans une filtre JSF ou un servlet filter)
    -apply request value
    -validation ok
    -update bean
    -action => déclenche un rollback => pas de commit
    -bean détaché mais à jour, juste pas stocké en DB

    requête 2:
    -bean réattaché au contexte
    -apply request value
    -validation failed => on arrête au niveau jsf
    -aucun rollback n'a été fait => commit => on stocke en db le résultat de requete 1!


    Bref, je ne sais pas trop quelles sont les recommendations pour faire ça proprement avec jsf / jpa / jta. Sachant que

    => Pour des raisons de délai et de lisibilité je préfère exploser mes Bean JPA directement à jsf plutot que de passer par des DTO très complexe à réaliser
    => Vu que l'édition se fait à travers plusieurs requêtes et que l'on ne sauve en gros que lorsque l'utilisateur clique sur "save", il ne peux y avoir un commit QUE dans ce cas là

    je peux évidement traiter toute la transaction à la main comme je le faisait avec hibernate, mais ça ne m'apparait pas le plus propre dans une contexte javaEE.

    Il me semble que si il est possible de dire à JTA que les transaction sont en rollback sauf commit explicite, ça me faciliterais le travail. Mais est-ce faisable?

  8. #8
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    Il me semble que s'il est possible de dire à JTA que les transaction sont en rollback sauf commit explicite, ça me faciliterais le travail. Mais est-ce faisable?
    Je dirais oui avec l'histoire de transaction locale (via @Resource)
    Ceci dit, je n'ai jamais essayé, je me base sur le fait que si tu utilises une transaction managée par le bean, sans commit explicite, il y a forcément un rollback.

  9. #9
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    j'essaierais de faire des tests ce soir avec un projet basique pour voir si j'arrive à quelque chose de propre.

  10. #10
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 938
    Points : 3 938
    Points
    3 938
    Par défaut
    Bonjour tout le monde,
    En fait la problématique posée dans ce post est tout à fait pertinente, et la solution bien que tchize ne le veuille pas c'est les DTO, il faut pouvoir décorréler les beans managés par JPA des beans exposés aux appelants, bien sûr derrière ça crée des soucis de perfs lors de la recopie d'objets, mais au moins on a une bonne couche sécurisant les opérations sur les entités liées à la base.Mais si c'est cette solution DTO n'est vraiment pas envisageable pour ton projet,nous dans nos projets voici comment on gère les transaction sur les méthodes des services exposés :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = TaClasseException.class)
    .
    Et pour info, même tu protèges autant que tu peux tes beans JPA des mauvaises actions qui ne doivent pas être commitées au niveau contrôleur, dis toi bien que ta couche métier peut être exposée demain sur un batch ou une autre application IHM, le même souci de protection de données se representera donc, bon je dis ça je dis rien .

  11. #11
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    Les problèmes de perfs ne sont pas un soucis. C'est surtout de la fiabilité des DTO dont je m'inquiète.
    l'application existe déjà => on essaie de minimiser les changements à apporter
    On a un gros bean JPA/Hibernate avec de nombreuses relations one-to-many et one-to-one bidirectionelles où les données à la fois du bean et de toutes les relations sont édités en même temps dans un énorme formulaire. Je n'ai, jusqu'à présent, trouvé aucun moyen efficace et surtout fiable, de travailler avec des data transfert object, malgré plusieurs essais à l'époque. Refaire manuellement toutes les propriétés et les relations, c'est un travail colossal pour être certains qu'on n'a pas commis une seule erreur de transfert. Faire ça en automatique, ça se vautre à chaque fois sur des edge cases. De plus, si je ne m'abuse, JSF est capable d'interpréter les règles de contraintes de JPA (notnull, etc) et de les valider directement, donc on perd ce bénéfice avec un DTO.

    Je pense qu'on peux arriver au DTO du pauvre en détachant tout de l'entitymanager et en finissant la transaction avec un merge, je vais faire des essais comme ça

    Quand à la protection, justement, j'aimerais la garder sur la couche service. Avec hibernante je n'avais aucun soucis à l'époque, le service se chargeait d'indiquer quand il fallait commiter. Avec l'inversion de la logique en JTA (rollback à expliciter), c'est plus problématique

  12. #12
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 938
    Points : 3 938
    Points
    3 938
    Par défaut
    Je ne connaissais pas ce souci de 'edge case', mais bon on apprend tous les jours.
    Nous dans nos projets, une fois que la couche des entités est mise en place, nous on a un petit outil moteur qui génère la couche DTO en partant de la couche des entités JPA, et ensuite nous utilisons le framework dozer pour faire de la recopie d'objets dans les 2 sens, et ça marche très bien. Je pense qu'en une heure torchée au lieu de chercher à contourner les DTO tu aurais déjà pu créer manuellement tes DTO, puisque c'est juste des classes à l'image de tes Pojo JPA, simplement que ce sont pas des entités au sens JPA . Pour la prise en main d'un outil de recopie il y'en a plusieurs désormais prêts à utilisation (comme orika moins lourd en perf). Et pour terminer même si JSF sait lire les annotations de validation JPA, personnellement je ne l'implémenterai point pour la simple raison que cela créerait une sorte de dépendance entre ta couche métier et ta couche contrôleur. Le jour où vous changez de framework contrôleur, vous pouvez oublier de ré-implémenter manuellement ces fonctionnalités qui étaient gérées nativement par l'ancien framework, pour moi cette validation doit se gérer dans les services métiers, lesquels ne sont même pas censés voir les entités, puisqu'ils doivent aussi passer par un DAO (ou EAO) .

  13. #13
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2006
    Messages
    3 274
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 3 274
    Points : 4 141
    Points
    4 141
    Par défaut
    Je n'ai sans doute pas tout compris mais dans mon cas je fais ceci: (OButterlin avait déjà évoqué cette possibilité)
    - cas 1 transactions gérées par le conteneur : une couche d'ejb stateless en @TransactionManagement(TransactionManagementType.CONTAINER), avec commit automatique hors exception
    - cas 2 transactions gérées par le bean : une couche d'ejb stateless en @TransactionManagement(TransactionManagementType.BEAN), je gère mes commits et rollbacks moi même, rien n'est automatique (j'imagine que la transaction part en timeout si pas explicitement commitéé, mais à vérifier)

  14. #14
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    Je pense qu'on peux arriver au DTO du pauvre en détachant tout de l'entitymanager et en finissant la transaction avec un merge, je vais faire des essais comme ça
    Je ne parlerais pas de DTO du pauvre, dans une application web, c'est même le cas par défaut (hors cas Stateful).
    Pour moi, les DTO permettent surtout d'avoir une abstraction/isolation de la partie "rendu" d'une application avec le modèle de données physique de la couche métier (et en particulier de la DB).
    Le merge devrait être utilisé systématiquement pour mettre à jour.

    A vrai dire, je ne comprends pas bien ton problème de base : si tu as une ancienne application et que tu ne veux pas passer trop de temps à modifier l'architecture (ça je comprends très bien ), le plus simple est de passer par des transactions gérées par le bean plutôt que le conteneur... ou encore plus simple, de ne pas la toucher du tout et d'attendre d'avoir du temps pour la refondre entièrement... mais bon, je ne connais pas tes impératifs

  15. #15
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par DevServlet Voir le message
    Et pour terminer même si JSF sait lire les annotations de validation JPA, personnellement je ne l'implémenterai point pour la simple raison que cela créerait une sorte de dépendance entre ta couche métier et ta couche contrôleur. Le jour où vous changez de framework contrôleur, vous pouvez oublier de ré-implémenter manuellement ces fonctionnalités qui étaient gérées nativement par l'ancien framework, pour moi cette validation doit se gérer dans les services métiers, lesquels ne sont même pas censés voir les entités, puisqu'ils doivent aussi passer par un DAO (ou EAO) .
    En fait, c'est surtout si la validation JPA changeait que tu aurais un problème, parce que si elle n'est plus prise en charge par la couche IHM, elle le sera quand même par la couche JPA, il y a peut-être une régression au niveau du rendu des erreurs, mais au moins tu ne corrompras pas la db.

    Cela dit, personnellement, si je devais choisir le meilleur système de validation, je le mettrais au niveau de la DB avec des triggers. Là au moins, c'est incontournable et centralisé.

Discussions similaires

  1. Gestion des transactions avec Spring-JPA ?
    Par kyf80 dans le forum JPA
    Réponses: 0
    Dernier message: 26/12/2010, 23h37
  2. Gestion des transactions avec les composants DOA
    Par lper dans le forum Bases de données
    Réponses: 2
    Dernier message: 01/12/2008, 16h06
  3. Réponses: 2
    Dernier message: 11/08/2008, 22h47
  4. [Data] gestion des transactions avec Spring Probleme
    Par mouvma dans le forum Spring
    Réponses: 2
    Dernier message: 02/04/2008, 20h39
  5. [ADO] j'ai du mal a utilisé des transaction avec Access
    Par aityahia dans le forum Bases de données
    Réponses: 11
    Dernier message: 20/06/2007, 16h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo