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

Hibernate Java Discussion :

Hibernate, problème d'update


Sujet :

Hibernate Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Février 2007
    Messages
    27
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 27
    Par défaut Hibernate, problème d'update
    Bonjour,

    Je rencontre un problème très étrange et je m'arrache les cheveux dessus depuis quelques jours.

    Pour résumer, lorsque je met à jour un champ d'un objet et que je fait un session.merge, ce n'est parfois pas le bon objet qui est mis à jour, ou parfois il met bien à jour mon objet mais m'en met à jour un autre avec des valeurs d'une mise à jour précédente ...

    Plus en détails :
    J'ai une table document, chaque document a une colonne ordre qui spécifie l'ordre d'affichage.
    Dans mon interface, j'ai des boutons haut/bas, pour faire passer un document au dessus/en dessous de celui du dessus/dessous. (donc modifier l'ordre des documents dans la liste)

    Quand l'utilisateur clique sur le bouton haut par exemple, je récupère dans la liste de documents affichée le document concerné par le clic, et celui du haut, puis je swappe les valeurs de la colonne "order" des deux documents, et je les sauvegarde (session.merge)

    Le résultat est que parfois la mise à jour n'a pas lieu, et d'autres documents de la liste sont modifiés arbitrairement avec des valeurs d'updates précédentes.

    D'après les tests que j'ai fait, mon code modifie bien les objets comme il faut, c'est au moment de mettre à jour la base de données avec hibernate que ca déconne ...

    De plus, dans les logs il y a parfois 3 ou 4 requêtes updates alors que mon code n'en appelle que 2 ...

    Clic sur un bouton
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    int y=coord.getY();
    Document currentDocument=list.get(y);
     
    int toSwapY=command.equals("up")?y-1:y+1;
    Document toSwapDocument=list.get(toSwapY);
     
    DocumentHandler.swapOrder(currentDocument, toSwapDocument);
    refreshDocumentList();
    Méthode swapOrder de DocumentHandler :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public static void swapOrder(Document doc1, Document doc2){
    	int tmpOrder=doc1.getOrder();
    	doc1.setOrder(doc2.getOrder());
    	doc2.setOrder(tmpOrder);
    	HibernateUtil.update(doc1);
    	HibernateUtil.update(doc2);
    }
    Méthode update de HibernateUtil :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public static void update(Object object){
    	Session session = HibernateUtil.currentSession();
    	Transaction tx= session.beginTransaction();
    	session.merge(object);
    	tx.commit();
    	HibernateUtil.closeSession();
    }
    Les méthodes equals et hashcode sont redéfinies pour Document (basées sur la clé primaire)

    Si quelqu'un pense avoir une idée d'où pourrait venir le problème, ou une piste ... là, j'avoue ne pas comprendre du tout ...

    Au pire je ferai une mise à jour en SQL, même si c'est un peu crasseux.

  2. #2
    Membre émérite
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    548
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2006
    Messages : 548
    Par défaut
    Fais un update() au lieu d'un merge()

    Sinon ta méthode HibernateUtil.update() n'est pas terrible parce que tu ouvres une transaction à chaque fois. Ce serait plus propre de faire la modification des deux objets dans une même transaction, histoire que si la 2e foire, tu ne te retrouve pas avec des données incohérentes.

  3. #3
    Membre averti
    Inscrit en
    Février 2007
    Messages
    27
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 27
    Par défaut
    Effectivement tu as raison, dans ce cas mieux vaudrait faire les deux updates au sein de la meme transaction, je change ca de suite

    Remplacer merge() par update() "ammeiliore" un peu mon problème, ca part en vrille moins souvent, mais j'ai toujours des updates indésirables, au lieu que ce soit une fois sur 2 c'est une fois sur 10 ...

    En regardant la trace SQL, je remarque aussi qu'il fait parfois des select avant de faire un update, j'avoue que je pige pas trop pourquoi ... surtout que les objets viennent d'être récupéres de la base

    Voilà les requêtes SQL exécutées dans les différents cas de figure :

    Quand ça marche, en utilisant update()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    select document0_.id as id2_0_, document0_.title as title2_0_, document0_."order" as order4_2_0_, document0_.language_id as language5_2_0_, document0_1_.catalogue_id as catalogue2_3_0_, document0_.type as type2_0_ from document document0_ left outer join volume document0_1_ on document0_.id=document0_1_.id where document0_.id=?
    update document set title=?, "order"=?, language_id=? where id=?
    select document0_.id as id2_0_, document0_.title as title2_0_, document0_."order" as order4_2_0_, document0_.language_id as language5_2_0_, document0_1_.catalogue_id as catalogue2_3_0_, document0_.type as type2_0_ from document document0_ left outer join volume document0_1_ on document0_.id=document0_1_.id where document0_.id=?
    update document set title=?, "order"=?, language_id=? where id=?
    Quand ca déconne, en utilisant update() (3 requêtes SQL générées pour 2 appel à update() ...)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    update document set title=?, "order"=?, language_id=? where id=?
    update document set title=?, "order"=?, language_id=? where id=?
    select document0_.id as id2_0_, document0_.title as title2_0_, document0_."order" as order4_2_0_, document0_.language_id as language5_2_0_, document0_1_.catalogue_id as catalogue2_3_0_, document0_.type as type2_0_ from document document0_ left outer join volume document0_1_ on document0_.id=document0_1_.id where document0_.id=?
    update document set title=?, "order"=?, language_id=? where id=?
    Quand ca marche, en utilisant merge()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    select document0_.id as id2_0_, document0_.title as title2_0_, document0_."order" as order4_2_0_, document0_.language_id as language5_2_0_, document0_1_.catalogue_id as catalogue2_3_0_, document0_.type as type2_0_ from document document0_ left outer join volume document0_1_ on document0_.id=document0_1_.id where document0_.id=?
    select document0_.id as id2_0_, document0_.title as title2_0_, document0_."order" as order4_2_0_, document0_.language_id as language5_2_0_, document0_1_.catalogue_id as catalogue2_3_0_, document0_.type as type2_0_ from document document0_ left outer join volume document0_1_ on document0_.id=document0_1_.id where document0_.id=?
    update document set title=?, "order"=?, language_id=? where id=?
    update document set title=?, "order"=?, language_id=? where id=?

    Quand ca déconne, en utilisant merge() (pareil, 3 updates au lieu de 2 ...)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    update document set title=?, "order"=?, language_id=? where id=?
    update document set title=?, "order"=?, language_id=? where id=?
    update document set title=?, "order"=?, language_id=? where id=?
    J'espère que c'est juste moi qui sais pas l'utiliser, et que hibernate est pas truffé de bugs ...

  4. #4
    Membre émérite
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    548
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2006
    Messages : 548
    Par défaut
    Tu fais ton update() dans une session qui vient d'être ouverte, donc cette session ne connait pas l'objet document et fait un select.

    Je pense que ta classe document a un lien vers un autre document (parent/fils ?) dans ce cas c'est probable que Hibernate cascade le update au fils/parent. Ca dépend de la façon dont tu as configuré ça dans le mapping (cascade="...")

    La façon la plus simple de travailler avec Hibernate est la suivante

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    ouvrir une session
    ouvrir une transaction
    try {
      charger les objets
      afficher et éventuellement modifier les objets
      commit de la transaction
    } catch (Exception e) {
      rollback de la transaction
    } finally {
     fermer la session
    }
    Si tu procédes comme ça tu n'as aucun update() ni merge() à appeler, Hibernate sait tout seul quels objets ont été modifiés et au moment du commit fait les modifications en base nécessaires.

    Sinon je te conseille de lire et relire le chapitre 10 de la doc ! http://www.hibernate.org/hib_docs/v3...jectstate.html

  5. #5
    Membre averti
    Inscrit en
    Février 2007
    Messages
    27
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 27
    Par défaut
    Merci pour ta réponse !

    Effectivement dans certains cas Document a une classe fille (Volume) Mais je ne modifie qu'une propriété de Document.

    J'ai résolu mon problème avec un update en HQL, toute autre méthode ne menant apparemment à rien.

    Je rencontre énormément de problèmes avec hibernate, par exemple un session.saveOrUpdate(obj) qui me génère une exception hibernate d'ID dupliqués alors que session.contain(obj) me renvoie false ...
    Enfin ca n'a pas de rapport avec ma question initiale.

    En fait j'aimerai bien comprendre comment c'est possible qu'il mette à jour les mauvais objets, j'aime pas résoudre les problèmes avec des palliatifs comme j'ai fait.

  6. #6
    Membre émérite
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    548
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2006
    Messages : 548
    Par défaut
    La méthode contains() te dit si cette instance est associée à la session. Ton problème est qu'une autre instance est déjà associée à la session.
    Il ne peut pas y avoir deux instances avec la même ID associée à une session.

  7. #7
    Membre extrêmement actif Avatar de Mister Nono
    Homme Profil pro
    Ingénieur Mathématiques et Informatique
    Inscrit en
    Septembre 2002
    Messages
    2 242
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur Mathématiques et Informatique
    Secteur : Santé

    Informations forums :
    Inscription : Septembre 2002
    Messages : 2 242
    Par défaut
    [quote=the-gtm;2488149]Tu fais ton update() dans une session qui vient d'être ouverte, donc cette session ne connait pas l'objet document et fait un select.

    Je pense que ta classe document a un lien vers un autre document (parent/fils ?) dans ce cas c'est probable que Hibernate cascade le update au fils/parent. Ca dépend de la façon dont tu as configuré ça dans le mapping (cascade="...")

    La façon la plus simple de travailler avec Hibernate est la suivante

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    ouvrir une session
    ouvrir une transaction
    try {
      charger les objets
      afficher et éventuellement modifier les objets
      commit de la transaction
    } catch (Exception e) {
      rollback de la transaction
    } finally {
     fermer la session
    }

    C'est comme cela que je fais dans mes application web et cela fonctionne très bien.

    A+

  8. #8
    Membre averti
    Inscrit en
    Février 2007
    Messages
    27
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 27
    Par défaut
    Bon j'ai réussi à faire tourner mon appli avec une session qui se ferme à la fin de l'exécution de la servlet, j'espère que c'est plus propre comme ça.

    Merci à tous !

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 13/01/2010, 12h22
  2. hibernate : problème avec update
    Par sel3aa dans le forum Hibernate
    Réponses: 3
    Dernier message: 17/02/2009, 10h02
  3. Problème d'update Mysql/Hibernate
    Par fid35 dans le forum Hibernate
    Réponses: 5
    Dernier message: 01/09/2008, 15h55
  4. Problème requete update
    Par krfa1 dans le forum Langage SQL
    Réponses: 2
    Dernier message: 29/03/2005, 08h47
  5. problème pour updater une BD
    Par yoda_style dans le forum ASP
    Réponses: 6
    Dernier message: 17/03/2005, 10h56

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