-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: Post-Commit-Update und refresh
PostPosted: Thu Nov 13, 2008 9:06 am 
Newbie

Joined: Mon Jul 14, 2008 5:31 am
Posts: 3
Hallo zusammen.

Ich möchte folgendes Problem in eine Zweischicht-Architektur (FAT-Client) lösen:
Bei einem RCP-Client gibt es verschiedene Views bzw. Editoren. Ich möchte pro View bzw. Editor je eine Hibernate-Session vergeben. Als Beispiel nehmen wir mal ein View die mir ein Liste mit allen im System hinterlegten Personen anzeigt. Ein Doppelklick auf einen Eintrag in der Liste öffnet den entsprechenden Editor der selektierten Person. Der Editor hat eine eigene Session und lädt die Person über die ID, welche er von der View geliefert bekommt. Jetzt ändere ich irgendwelche Parameter an der Person und speichere den Editor. Jetzt möcht ich das die Session der View diese Änderung mitbekommt und das entsprechende Objekt "refreshed".
Dazu hänge ich mich als Listener hinter den Commit:

Code:
Configuration config = new Configuration();
   config.getEventListeners()
   .setPostCommitUpdateEventListeners(
   new PostUpdateEventListener[] { new MyPostUpdateEventListener() });

...

   private static class MyPostUpdateEventListener implements
         PostUpdateEventListener {

      public void onPostUpdate(PostUpdateEvent event) {
         for (Session session : sessions) {
            if (!session.equals(event.getSession())) {
               session.refresh(event.getEntity());
            }
         }
      }
   }



D.h. ich halte mir alle geöffneten Sessions in einer Liste. Bei einem Commit nach einem Update mache ich ein Refresh auf alle anderen Sessions (kann man noch optimieren auf die Sessions die das Objekt beeinhalten, lasse ich hier aber weg).
Das ganze funktioniert auch eigentlich wunderbar. Wenn ich debugge wird während des commit der Listener aufgerufen. Auch wird ein select ausgeführt beim refresh. Das Problem ist, dass das Objekt in der ersten Session nicht aktualisiert ist und das obwohl der Listener "post commit" ausgeführt werden soll.
Zum besseren Verständnis folgender Code:
Code:
      Session s1 = hh.getNewSession();
      Transaction t1 = null;
      Session s2 = hh.getNewSession();
      Transaction t2 = null;
      Person p = null;
      try {
// Person anlegen
      t1 = s1.beginTransaction();
         p = new Person();
         p.setName("a");
         p.setVorname("b");
         s1.save(p);
         t1.commit();
      } catch (Exception e) {
         e.printStackTrace();
         if (t1 != null) {
            t1.rollback();
         }
         
      }
      try {
// Person mit der zweiten Session aktualisieren
         t2 = s2.beginTransaction();
         Person tmp = (Person) s2.get(Person.class, p.getId());
         tmp.setName("AAA");
         s2.update(tmp);
         t2.commit();
      } catch (Exception e) {
         e.printStackTrace();
         if (t2 != null) {
            t2.rollback();
         }
      }
      try {
// Person aus der ersten Session auslesen
         t1 = s1.beginTransaction();
         Person tmp = (Person) s1.get(Person.class, p.getId());
         System.out.println("Before Refresh: " + tmp.getName());
         s1.refresh(tmp);
         System.out.println("After Refresh: " + tmp.getName());
         t1.commit();
      } catch (Exception e) {
         e.printStackTrace();
         if (t1 != null) {
            t1.rollback();
         }
      }



Und hier die entsprechende Ausgabe der Console:

Hibernate: insert into PERSON (NAME, VORNAME, ID) values (?, ?, ?)
Hibernate: select person0_.ID as ID0_0_, person0_.NAME as NAME0_0_, person0_.VORNAME as VORNAME0_0_ from PERSON person0_ where person0_.ID=?
Hibernate: update PERSON set NAME=?, VORNAME=? where ID=?
Hibernate: select person0_.ID as ID0_0_, person0_.NAME as NAME0_0_, person0_.VORNAME as VORNAME0_0_ from PERSON person0_ where person0_.ID=?
Before Refresh: a
Hibernate: select person0_.ID as ID0_0_, person0_.NAME as NAME0_0_, person0_.VORNAME as VORNAME0_0_ from PERSON person0_ where person0_.ID=?
After Refresh: AAA

Das erste Insert stammt von der Anlage der Person.
Das erste select ist das laden der Person in die zweite Session.
Dann kommt das update aus der zweiten Session.
Das nächste select wird vom Listener ausgelöst (session.refresh()).
Dann gebe ich den Namen der Person aus der ersten Session aus. Hier ist genau das Problem. Der Name ist nicht aktuell.
Dann mache ich ein explizites refresh auf die Person in der ersten Session.
Und siehe da, der Name stimmt.

Kann mir einer sagen was ich falsch mache? Warum funktioniert nicht schon der refresh aus dem Listener obwohl das Select ausgeführt wird?

Vielen Dank!


Top
 Profile  
 
 Post subject: Re: Post-Commit-Update und refresh
PostPosted: Fri Nov 14, 2008 5:07 am 
Newbie

Joined: Mon Jul 14, 2008 5:31 am
Posts: 3
Habe das Problem gelöst.

Der Fehler liegt im Listener. Genauer gesagt in dem was ich refresh'e. Ich habe ein refresh auf das Objekt gemacht, das im Event hängt. Das ist aber die Instanz aus der anderen Session.
Ich muss mir also zuerst über die ID das Objekt in der jeweiligen Session an Land ziehen und darauf den refresh aufrufen:

Code:

private static class MyPostUpdateEventListener implements PostUpdateEventListener {

  public void onPostUpdate(PostUpdateEvent event) {
    for (Session session : sessions) {
      if (!session.equals(event.getSession())) {
        //session.refresh(event.getEntity());
        Object o = session.get(event.getEntity().getClass(), entity.getId());
        session.refresh(o);
      }
    }
  }
}


Der Vollständigkeit halber hier noch die Lösung die erst nachschaut ob das Objekt auch wirklich in der Session referenziert ist.

Code:
public void onPostUpdate(PostUpdateEvent event) {
  for (Session session : sessions) {
    if (!session.equals(event.getSession())) {
      SessionStatistics stats = session.getStatistics();
      Set<EntityKey> keys = stats.getEntityKeys();
      if (keys != null) {
        for (EntityKey nextKey : keys) {
          Serializable id = nextKey.getIdentifier();
          if (id.equals(event.getId())) {
            Object o = session.get(event.getEntity().getClass(), event.getId());
            session.refresh(o);
          }
        }
      }
    }
  }
}


Viele Grüße


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 20, 2008 4:35 am 
Expert
Expert

Joined: Tue Nov 23, 2004 7:00 pm
Posts: 570
Location: mostly Frankfurt Germany
Nur ein Hinweis: die Session ist nicht threadsafe !

_________________
Best Regards
Sebastian
---
Training for Hibernate and Java Persistence
Tutorials for Hibernate, Spring, EJB, JSF...
eBook: Hibernate 3 - DeveloperGuide
Paper book: Hibernate 3 - Das Praxisbuch
http://www.laliluna.de


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.