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!