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

Spring Java Discussion :

javax.persistence.RollbackException: Transaction marked as rollbackOnly [Data]


Sujet :

Spring Java

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    759
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 759
    Points : 159
    Points
    159
    Par défaut javax.persistence.RollbackException: Transaction marked as rollbackOnly
    Bonjour,

    J'ai migré une appli de vieilles librairies à des librairies un peu plus à jour.
    J'ai un souci quand je veux supprimer une ligne dans une table (toute simple sans clé étrangère ou autre).

    Je finis dans GenericJpaDAO.jabva par appeler (comme avant) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    	public void deleteObject(Object object) {
    		try {
    			em.remove(object);
    		} catch (Exception e) {
    			em.remove(em.merge(object));
    		}
    	}
    Dans le service
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	public void deleteMySpecificObject(MySpecificObject obj) {
    		myDAO.deleteObject(obj);
    	}
    Au cas où ça serve, comme avant le service est déclaré comme tel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
    public class MyService implements IMysService {
    ...
    }
    J'arrive pas à trouver de solution pour comprendre ce qui provoque ça.
    L'insertion d'une nouvelle ligne fonctionne bien et sa modification également, mais la suppression ne marche plus...

    EDIT : si je remplace par em.remove(object); par em.remove(em.merge(object)); --> ça marche de nouveau.
    Autrement dit mon Exception n'était pas catchée et donc maintenant la fonction remove ne marche plus tant qu'un merge n'est pas fait avant.
    -->si quelqu'un peu m'expliquer car je ne suis pas très confiant d'avoir du flou dans ma couche bas niveau...


    Merci.

  2. #2
    Membre confirmé Avatar de Lordsephiroth
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    199
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Suisse

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

    Informations forums :
    Inscription : Mai 2006
    Messages : 199
    Points : 494
    Points
    494
    Par défaut
    Bonjour,
    D'après ce que je comprends, le changement de comportement n'est pas lié directement avec Spring mais plutôt avec JPA/Hibernate. La différence entre em.remove() et em.remove(em.merge()) tient dans la gestion du statut de l'objet dans la session Hibernate.

    Voici un petit lien qui explique les différents statuts de session hibernate.

    La fonction "merge" sert, comme son nom l'indique, à fusionner l'objet entité qui se trouve en session Hibernate et l'objet entité qui se trouve en statut "detached". La base est également mise à jour pour refléter le changement effectué dans la session Hibernate. On peut dire que "merge" effectue la fusion puis un appel à "update".
    Dans votre exemple, il me semble que l'entité donné à la méthode de persistance est en statut "detached". Hibernate mentionne donc par une Exception que l'objet n'est pas attaché à la session et qu'il ne peut donc pas le supprimer. Chose que vous avez "cachée" dans la directive catch derrière l'appel à "merge" qui réinsère l'objet en session.

    Un petit conseil toutefois, vous devriez de préférence effectuer un code comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    MyObject entity = em.find(MyObject.class, object.getPrimaryKey());
    em.remove(entity);
    Ce code devrait faire la même chose, sauf qu'à la place de "merge" en session Hibernate l'objet (processus lent, notamment à cause des vérifications de type "stale-checks"), il va rechercher par clé primaire l'objet en session Hibernate (rapide) puis faire le remove (à faire dans tous les cas). Le code ne nécessite également pas de try-catch, processus à nouveau relativement lent (quoique généralement négligeable en comparaison des accès à la DB).

    Il se peut que les librairies Hibernate ait légèrement changé de comportement au fil du temps et qu'auparavant la fonction "remove" acceptait la suppression des entités en statut detached. Ou alors que pour une raison quelconque lié à votre migration, l'entité est maintenant en statut "detached" alors que ce n'était pas le cas auparavant.

    En espérant ne pas m'être trompé dans l'analyse en fonction des informations fournies (ce qui précède n'est qu'une supposition qui pourrait être confirmée si le code que je propose par "find" puis "remove" remplace effectivement le code "remove(merge)").
    Always code as if the guy maintaining your application is a violent psychopath!
    Site personnel sur la saga Final Fantasy : http://www.final-fantasy.ch

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    759
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 759
    Points : 159
    Points
    159
    Par défaut
    OK merci.

    Concrètement, cela donne quoi pour ma fonction générique deleteObject car le getPrimaryKey n'existe pas pour un objet

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public void deleteObject(Object object) {
    		Object entity = em.find(object.getClass(), object.getPrimaryKey());
    		em.remove(entity);
    	}

  4. #4
    Membre confirmé Avatar de Lordsephiroth
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    199
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Suisse

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

    Informations forums :
    Inscription : Mai 2006
    Messages : 199
    Points : 494
    Points
    494
    Par défaut
    Dans ton code il te faut remplacer "object.getPrimaryKey()" par le getter de ta clé primaire (simple ou composite). Si tu veux une méthode aussi générique que "remove(Object o)", tu vas devoir créer une interface (ou une classe abstraite) permettant d'accéder de manière générique à ta clé primaire.
    Par exemple si ta clé primaire est un attribut long nommé "id", tu as probabablement un getter getId() sur tous tes entités. Dans ce cas, crée une interface IEntity qui contient simplement les getter/setter getId() et setId(). Fais en sorte que tes entités implémentent cette interface. Ton code devient alors :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public void deleteObject(IEntity entity) {
        IEntity e = (IEntity) em.find(entity.getClass(), entity.getId());
        if(e != null)
            em.remove(e);
        else
            // peut être throw(IllegalStateException) si tu souhaites être averti d'une éventuelle tentative pour supprimer un entité qui n'existe pas.
    }
    Always code as if the guy maintaining your application is a violent psychopath!
    Site personnel sur la saga Final Fantasy : http://www.final-fantasy.ch

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    759
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 759
    Points : 159
    Points
    159
    Par défaut
    Hum, ça me paraît pas très générique : il faudrait que tous les objets aient une clé qui s'appelle "id", sans compter les PK composites.

    Je vais donc rester sur em.remove(em.merge(object));

  6. #6
    Membre confirmé Avatar de Lordsephiroth
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    199
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Suisse

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

    Informations forums :
    Inscription : Mai 2006
    Messages : 199
    Points : 494
    Points
    494
    Par défaut
    Rien n'empêche de mettre une fonction getId() plus générique avec une interface comme ceci :
    et dans une entité où la clé primaire serait composite et nommé "compositePrimaryKey" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    @Override
    Object getId(){
      return this.getCompositePrimaryKey();
    }
    je donnais l'exemple de la clé primaire de type "long" car c'est le type le plus couramment utilisé.
    Always code as if the guy maintaining your application is a violent psychopath!
    Site personnel sur la saga Final Fantasy : http://www.final-fantasy.ch

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    759
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 759
    Points : 159
    Points
    159
    Par défaut
    OK, why not.

    Je laisse les autres faire leur choix.
    Moi si ça marche je m'évite du code en plus ;-)

    Merci en tous cas.

  8. #8
    Membre averti
    Inscrit en
    Octobre 2005
    Messages
    135
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 135
    Points : 391
    Points
    391
    Par défaut
    Citation Envoyé par Lordsephiroth Voir le message
    Rien n'empêche de mettre une fonction getId() plus générique avec une interface comme ceci :
    et dans une entité où la clé primaire serait composite et nommé "compositePrimaryKey" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    @Override
    Object getId(){
      return this.getCompositePrimaryKey();
    }
    je donnais l'exemple de la clé primaire de type "long" car c'est le type le plus couramment utilisé.
    Object !!! haaa!!! hérétique,au bucher !!!

    Type générique serai un poil plus sympa quand même.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    public interface Entity<T> {
            T getId();
    }
    Tu peut même pousser le vice a
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <T extend Serializable>
    .

  9. #9
    Membre confirmé Avatar de Lordsephiroth
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    199
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Suisse

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

    Informations forums :
    Inscription : Mai 2006
    Messages : 199
    Points : 494
    Points
    494
    Par défaut
    Citation Envoyé par bilgetz Voir le message
    Object !!! haaa!!! hérétique,au bucher !!!
    J'avoue... la solution en utilisant un type générique T est bien meilleure que Object.
    Je m'en vais de ce pas me fouetter !
    Always code as if the guy maintaining your application is a violent psychopath!
    Site personnel sur la saga Final Fantasy : http://www.final-fantasy.ch

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 3
    Dernier message: 02/12/2008, 11h39
  2. Réponses: 5
    Dernier message: 01/12/2008, 01h14
  3. [Hibernate 3] javax.persistence.PersistenceException
    Par Sensei.f dans le forum Hibernate
    Réponses: 1
    Dernier message: 21/11/2007, 16h52
  4. [EJB3 Entity] Usage de persist() en transaction ou sans ?
    Par tiamat dans le forum Java EE
    Réponses: 2
    Dernier message: 17/10/2007, 07h52
  5. Tomcat + JPA (javax.persistence)
    Par balmeyer dans le forum Tomcat et TomEE
    Réponses: 6
    Dernier message: 01/02/2007, 13h00

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