Hibernate ist ein hochentwickeltes ORM-Framework, das den Zustand Ihrer persistenten Daten für Sie verwaltet. Die wichtige, aber schwierige Aufgabe der Verwaltung des persistenten Zustands Ihrer Anwendung an ein Framework zu übergeben, hat zahlreiche Vorteile. Einer der Nachteile ist jedoch, dass Sie gewissermaßen die Kontrolle darüber verlieren, was wo und wann passiert. Ein Beispiel dafür ist die Funktion Dirty Checking, die Hibernate bietet. Mit der Dirty Checking-Funktion ermittelt Hibernate, welche Daten in Ihrer Datenbank aktualisiert werden müssen. In vielen Fällen ist diese Funktion sehr nützlich und funktioniert ohne Probleme, aber manchmal kann es vorkommen, dass Hibernate etwas aktualisiert, was Sie nicht erwartet haben. Herauszufinden, warum das passiert ist, kann eine ziemlich schwierige Aufgabe sein.
Ich wurde neulich gebeten, ein Problem mit einer StaleObjectState-Ausnahme zu untersuchen. StaleObjectState-Ausnahmen werden von Hibernate verwendet, um einen optimistischen Sperrkonflikt zu signalisieren: Während ein Benutzer (oder Prozess) versucht, ein Datenelement zu speichern, wurde dasselbe Datenelement in der zugrunde liegenden Datenbank seit dem letzten Lesen bereits geändert. Das Problem war nun, dass der Prozess, der die Ausnahme auslöste, der einzige Prozess war, der diese Daten ändern sollte. Aus funktionaler Sicht kann es keinen anderen Benutzer oder Prozess gegeben haben, der die Daten in der Zwischenzeit geändert hat. Was war also los?
Als wir einige Zeit im Protokoll herumstöberten, fanden wir heraus, dass die Daten von einem anderen Prozess aktualisiert wurden, der diese Daten eigentlich nur lesen sollte. Irgendwie beschloss Hibernate, dass die von diesem Prozess gelesenen Daten schmutzig geworden waren und gespeichert werden sollten. Jetzt musste er also herausfinden, warum Hibernate diese Daten für schmutzig hielt.
Hibernate kann an mehreren Stellen in einer Anwendung eine Schmutzprüfung durchführen:
- Wenn eine Transaktion übertragen oder eine Sitzung geleert wird, denn zu diesem Zeitpunkt sollten die in der Transaktion oder Sitzung vorgenommenen Änderungen in der Datenbank gespeichert werden.
- Wenn eine Abfrage ausgeführt wird. Um zu verhindern, dass Änderungen, die sich noch im Speicher befinden, übersehen werden, flusht Hibernate Daten, die abgefragt werden könnten, kurz vor der Ausführung der Abfrage in die Datenbank. Dabei versucht Hibernate, wählerisch zu sein und nicht immer alles zu flushen, sondern nur die Daten, die abgefragt werden könnten.
- Der DefaultFlushEntityEventListener bestimmt, welche Felder verschmutzt sind. Die Interna dieser Klasse arbeiten mit der Liste der Eigenschaften einer Entität und zwei Listen von Werten: die Werte, wie sie aus der Datenbank geladen wurden, und die Werte, wie sie derzeit in der Sitzung bekannt sind. Sie delegiert die Ermittlung der 'Verschmutzung' eines Feldes an den registrierten Abfangjäger und an die Typen der Eigenschaften.
- Die EntityUpdateAction ist für die Aktualisierung selbst verantwortlich. Ein Objekt dieses Typs wird zu einer ActionQueue hinzugefügt, die ausgeführt wird, wenn eine Sitzung geleert wird.
Verfasst von
Maarten Winkels
Contact
Let’s discuss how we can support your journey.