Hibernate version:
3.1
Hallo zusammen,
hat jemand eine Idee, wie ich möglichst effizient eine (grosse) Menge an Objekten aktualisieren kann?
Hintergrund:
In einer Rich-Client-Anwendung sollen u.a. Stammdaten in Listen angezeigt werden. Das Vorgehen hierbei (siehe auch Code-Beispiel):
1. Session anlegen
2. Transaktion beginnen
3. Query erzeugen und Liste von dieser abholen
4. Transaktion enden
Die erhaltene Liste soll nun aktualisiert werden, d.h. Query an die Datenbank schicken, so dass alle bereits vorhandenen Objekte mit dem neuesten Stand aus der Datenbank gefüllt sind und potentiell neue Objetke mit in die Liste aufgenommen werden. Dazu wird wieder wie oben beschrieben vorgegangen. Leider werden bei erneuten Suchvorgängen bereits in der Session bekannte Objekte nicht aktualisiert, ihr Zustand bleibt unverändert (siehe Ergbnis, alle Objekte mit ID 1..4 sind nicht aktualisiert worden. Im Codebeispiel wurde absichtlich zuerst nur ein Teilmenge in der ersten Query angefordert, damit in der Ergebnisausgabe die unterschiedlichen Zustände deutlicher werden.).
Configuration
Code:
Configuration cfg = new Configuration().addFile(...);
cfg.setProperty("hibernate.cache.use_second_level_cache","false");
Mapping documents:Code:
<class name="TestA" table="testa">
<id name="id"> <generator class="assigned"/></id>
<version name="changenumber" unsaved-value="null" type="java.lang.Long"/>
<property name="textA"/>
<property name="textB"/>
</class>
TestA.changenumber wird bei updates durch die DB um 1 erhöht (Trigger).
Code between sessionFactory.openSession() and session.close():Code:
Session session = ...
Transaction tx = session.beginTransaction();
//Laden einer Teilmenge von TestA
List<TestA> list = (List<TestA>) session.createQuery("from TestA item where item.id<5").list();
tx.commit();
//Simulation von Aenderungen an der Gesamtmenge von TestA durch einen anderen Thread
Connection con = ....getConnection();
con.createStatement().executeUpdate("update testa set texta='after' ");
con.commit();
con.close();
//Ende Simulation
//hier potentielles Aktualisieren der bereits in Liste list vorhandenen Objekte - siehe Codebeispiel weiter unten - durch session.refresh(...)
//Erneutes Laden, diesmal jedoch die Gesamtmenge von TestA
tx = session.beginTransaction();
List<TestA> list2 = (List<TestA>) session.createQuery("from TestA ").list();
for (TestA item:list2) {
System.out.println(item.getId()+"|"+item.getChangenumber());
}
Ergebnis:
id | text | changenumber
1|before|1
2|before|1
3|before|1
4|before|1
5|after|2
6|after|2
7|after|2
Das Problem lässt sich sehr leicht lösen, indem ich ALLE bereits vorhandenen Objekte vor oder auch nach dem erneuten Absetzen einer Query durch Session.refresh(item) aktualisiere.
Code:
for (TestA item:list){
session.refresh(item);
}
...
Ergebnis :
id | text | changenumber
1|after|2
2|after|2
3|after|2
4|after|2
5|after|2
6|after|2
7|after|2
Beim jedem Aufruf von session.refresh(...) wird jedoch (soweit ich es nachvollzogen habe) immer ein SQL-Statement gegen die Datenbank geschickt. Das führt also bei rel. mächtigen Mengen an Objekten zu einer enormen und vor allem nicht notwendigen Last und erhöhten Gesamtdauer der Aktualisierung.
Gibt es die Möglichkeit, der Session mitzuteilen, dass bei einer Query auch bereits vorhandene Objekte mit den "neuen" Werten aktualisiert werden sollen? Oder sind nur die beiden Alternativen vorhanden:
a) für jedes bereits in der Session bekannte Objekt ein session.refresh(objekt) aufrufen
b) alle bereits vorhandenen Objekte aus der Session entfernen (evict) und neue Objekte durch die Query erzeugen lassen, mit dem Nachteil, dass alle Referenzen auf die "alten" und entfernten Objekte ungültig werden (aus der Gui, etc.)
Für jeden Hinweis bin ich dankbar!