2011-11-18 3 views
0

J'essayais de connaître les différents états d'objets dans Hibernate. J'ai essayé ce qui suit et je n'ai pas trouvé d'explication au comportement montré. Quelqu'un peut-il aider?Comportement d'objets persistants Hibernate

Voici ce que j'essaie de faire: Insérer un nouvel enregistrement dans la table des employés (empId étant la clé primaire). Dans la même transaction, mettez à jour l'enregistrement nouvellement ajouté (à l'aide d'une requête, en modifiant nomImpl). Puis, lorsque je vérifie la propriété empName de l'objet persistant, elle continue à afficher l'ancienne valeur empName. Étant un objet persistant, je m'attendais à ce qu'il reflète la modification apportée à la base de données. Je ne pouvais pas comprendre pourquoi ça ne l'était pas. (Mon fichier de configuration hibernate a tout réglé par défaut, sauf pour la propriété "hibernate.hbm2ddl.auto" définie comme mise à jour) Cependant, après avoir fait la mise à jour, quand j'ai défini le nom empName de l'objet persistant avec la valeur retournée par getEmpName (qui s'affiche comme old empName value par sysout), les données finales de la table affichent la nouvelle valeur empName (c'est-à-dire celle que j'ai mise à jour en utilisant hql). S'il vous plaît faites référence au code pour cela:

Transaction tx = session.getTransaction(); 
    tx.begin(); 

    Employee e1 = new Employee(); 
    e1.setEmpId(1); 
    e1.setEmpName("Jack"); 
    e1.setEmpAge(25); 
    session.save(e1); 
    System.out.println("before: "+e1.getEmpName()); //prints Jack 
    session.createQuery("update Employee set empName = \'Jack_new\' where id=1").executeUpdate(); 
    System.out.println("after: "+e1.getEmpName()); //prints Jack 
    e1.setEmpName(e1.getEmpName()); //should update database 
    tx.commit(); //sets empName value to Jack_new, as seen in table 
    System.out.println("last: "+e1.getEmpName()); //prints Jack 

Répondre

5

De the hibernate documentation:

Manipulation des données directement dans la base de données (en utilisant le langage de manipulation de données SQL (DML) les états: INSERT, UPDATE, DELETE) n'affectera pas l'état en mémoire.

Lorsque vous utilisez la DML directe suivant la mise à jour,

session.createQuery("update Employee set empName = \'Jack_new\' where id=1").executeUpdate(); 

il sera court-circuite le contexte de persistance Hibernate (et tous les caches). Ainsi, bien que le empName soit mis à jour dans Jack_new dans la base de données, son instance dans le contexte de persistance conserve toujours l'ancienne valeur.

Vous pouvez utiliser session.refresh(e1); pour relire les valeurs de la e1 de la base de données sous-jacente telle que e1.empName sera mise à jour à Jack_new.

Normalement, nous n'écrivons pas manuellement les instructions UPDATE pour effectuer la mise à jour. Il suffit de définir les valeurs mises à jour sur les propriétés des instances persistantes. Pendant le vidage, Hibernate effectue la vérification sale, génère et publie la mise à jour SQL correspondante automatiquement pour mettre à jour ces instances corrompues.


(Répondre au commentaire):

Cependant, juste avant de faire tx.commit() Je suis en train e1.empName à l'ancienne valeur (qui est la valeur retournée par e1.getEmpName ()). La valeur finale vue dans la base de données est toujours la nouvelle valeur.

/**e1 become persisted after save()**/ 
session.save(e1); 

/**e1.empName is updated to new value in the DB , but as the direct DML 
will not affect in-memory state , e1.empName in the java side 
still keeps the old value***/ 
session.createQuery("update Employee set empName = \'Jack_new\' where id=1").executeUpdate(); 

/** As you only set `e1.empName` to its original value , the values of `e1` do 
not have any changes. Thus , during the flushing (which occurs at the moment 
before `commit()`) , hibernate will consider that `e1` is not dirty and 
hence no update SQL will be generated and issued to update e1 . 
***/ 
e1.setEmpName(e1.getEmpName()); 

Ainsi, le résultat est que Jack_new est enregistré dans la base de données.

+0

Merci pour vos commentaires Dmitry et Ken. M'a aidé à comprendre la plupart du problème. Cependant, juste avant de faire tx.commit(), je mets e1.empName à l'ancienne valeur (c'est-à-dire la valeur renvoyée par e1.getEmpName()) .Toutefois, la valeur finale vue dans la base de données est la nouvelle valeur. – Leo

+0

Vous êtes les bienvenus, voir ma mise à jour plz –

+0

Merci Ken. Cela rend tout clair. – Leo

1

vous exécutez une requête directe contre la base de données changer la valeur d'un champ derrière le dos de mise en veille prolongée. Lorsque vous faites cela, vous ne serez pas modifié magiquement sa valeur enregistrée, qui est le nom d'origine. Donc, quand vous faites "e1.setEmpName (e1.getEmpName());" vous rétablissez le nom à la valeur d'origine.

+0

Merci. Cependant, juste avant de faire tx.commit(), je configure e1.empName à l'ancienne valeur (c'est-à-dire la valeur renvoyée par e1.getEmpName().) La dernière valeur vue dans la base de données est toujours la nouvelle valeur. – Leo