Warum gibt meine Hibernate-Abfrage veraltete Daten zurück?
-
16-11-2019 - |
Frage
Schnellversion
Im Grunde aktualisiere ich eine Ruhezustandstabelle und nachfolgende Abfragen laden einen veralteten Wert.
Detaillierte Version
Hibernate (3.3.1.GA) und EhCache (2.4.2).
Beharrte Book
Objekt mit a List<PageContent>
Seitenzahl und ich füge eine Seite in der Mitte dieses Buches hinzu.Ich verwende Databinder/Wicket, obwohl ich nicht glaube, dass das damit zusammenhängt.
public void createPageContent(Book book, int index) {
Databinder.getHibernateSession().lock(book, LockMode.UPGRADE);
PageContent page = new PageContent(book);
book.addPage(page, index);
CwmService.get().flushChanges(); // commits the transaction
}
Die anwendbaren Felder/Methode in Book
Sind:
@OneToMany
@JoinColumn(name="book_id")
@IndexColumn(name="pageNum")
@Cascade({CascadeType.ALL, CascadeType.DELETE_ORPHAN})
private List<PageContent> pages = new ArrayList<PageContent>();
public synchronized void addPage(PageContent page, int index) {
pages.add(index, page);
}
Das Endergebnis ist, dass einer Liste eine neue Seite hinzugefügt wird und die Datenbank entsprechend aktualisiert wird, und ich habe dies in meinem Datenspeicher bestätigt.Bei der nächsten Abfrage für eine Seite, beispielsweise „Seite Nr. 4“, wird jedoch die „alte“ Seite Nr. 4 anstelle der neuen Seite Nr. 4 geladen:
criteria.add(Restrictions.eq("book", book));
criteria.add(Restrictions.eq("pageNum", pageNum));
criteria.setCacheable(true);
Daher entferne ich widerwillig Caching aus den Kriterien.Es fragt den Datenspeicher ab, aber gibt immer noch den falschen Wert zurück.Wenn ich jedoch in beiden Fällen etwa 2 Minuten warte, funktioniert alles wie erwartet.Ich gehe davon aus, dass es immer noch um Caching geht.Beide PageContent
Und Book
Verwenden Sie diese Caching-Strategie:
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
Ich gestehe, ich bin neu im Caching und habe diese Datei gerade zum ersten Mal eingerichtet.Hier ist meine ehcache.xml:
<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" statistics="false"/>
<!-- Hibernate's Cache for keeping 'lastUpdated' data on each table. Should never expire. -->
<cache name="org.hibernate.cache.UpdateTimestampsCache" eternal="true" />
<!-- Hibernate's Query Cache - should probably be limited -->
<cache name="org.hibernate.cache.StandardQueryCache" maxElementsInMemory="1000" />
AKTUALISIEREN:Entferne den @Cache
Anmerkungen zu meinen Datenspeicherobjekten beseitigen das Problem.Natürlich möchte ich diese Objekte zwischenspeichern, da Seitenänderungen viel seltener sind als Zugriffe.
Also, Gedanken?Es gibt auch mehrere andere damit verbundene Probleme, unter anderem beim Löschen von Seiten.Alles aktualisiert die Datenbank wie erwartet, aber das tatsächliche Verhalten ist seltsam.
Dank im Voraus!
UPDATE Nr. 2:Durch das Debuggen kann ich bestätigen, dass der Datenspeicher über die richtigen Informationen verfügt, und wenn die Abfrage ausgeführt wird, greift sie auf den Second-Level-Cache zurück, der fehlerhafte Informationen enthält.Ich gehe davon aus, dass es nicht an mir liegt, jedes Mal, wenn sich die Daten ändern, den Cache zu löschen?
Lösung 2
Ich habe das Problem entdeckt, aber es bringt etwas anderes mit sich.
Grundsätzlich gilt: Beim Ändern von a Book
Objekt List<PageContent>
Feld macht Hibernate drei Dinge:
- Lässt den TimeStamp-Cache-Eintrag für beide ablaufen
Book
UndPageContent
- Führt viele Abfragen durch, um das zurückzusetzen
pageNum
Feld auf jedemPageContent
Objekt - Entfernt die
Book
Objekt aus dem Second Level Cache.
Dadurch wird sichergestellt, dass nachfolgende Abfragen nach neuen Objekten usw. suchen.Jedoch:
- Der Ruhezustand entfernt nicht jede neu nummerierte Datei
PageContent
Objekt aus dem Second Level Cache
Infolgedessen wird jede Abfrage für die Seitenliste ordnungsgemäß ausgeführt, greift dann jedoch auf veraltete Second-Level-Cache-Werte für die tatsächlichen Daten zurück.
Ich vermute, das liegt daran, dass sich Hibernate a anfühlt pageNum
Veränderung ist keine Änderung der Daten, sondern eine Änderung des Managements hinter den Kulissen.Das sind jedoch die Daten, die ich lesen und anzeigen möchte.
Die Lösung besteht darin, jede Seite nach dem Einfügen/Löschen manuell zu aktualisieren.
Andere Tipps
Nach CwmService.get().flushChanges(); // commits the transaction
Führen Sie ein explizites Commit durch.flush()
Die Änderungen werden nur in die Datenbank geschrieben, aber nicht festgeschrieben.Ich bin mir nicht sicher flushChanges()
obwohl.