Das O/R-Mapping von Hibernate ist eine feine Sache, insbesondere bei Relationen: Hat eine Klasse Schrank
eine 1:n-Beziehung mit einer Klasse Schublade
, dann liefert mir einSchrank.getSchubladen()
eine Collection von Objekten der Klasse Schublade
. So sieht es jedenfalls aus, aber das muss man mit Vorsicht genießen.In Wirklichkeit handelt es sich um Proxy-Objekte, die mir Hibernate unterschiebt. Diese Objekte tun nur so, als wären sie Schubladen. Das Framework muss nämlich vermeiden, durch das Auflösen von Relationen im Endeffekt die gesamte Datenbank einzulesen. Ein gutes Beispiel dafür ist ein Familienstammbaum, in dem alle Personen durch Eltern-, Kind- oder sonstige Relationen verbunden sind. Würde Hibernate die alle auflösen, nur weil ich von einer Person den Namen haben will, hätte ich sofort die ganze Familiengeschichte am Hals.
Deshalb realisiert Hibernate mittels der erwähnten Proxyobjekte eine sog. "Lazy initialization": Bei der Initialisierung abhängiger Objekte schiebt Hibernate das Nachladen der Daten so lange auf, bis sie von der Anwendung wirklich abgefragt werden. Das SELECT
auf die Schubladen-Tabelle wird nicht schon bei einSchrank.getSchubladen
abgesetzt, sondern erst, wenn ich auf die Daten einer dieser Schubladen zugreife.
Und da wartet eine Falle: Dieses "Nachladen auf den letzten Drücker" muss in der gleichen Session passieren wie das Laden des übergeordneten Objekts. Wurde die Session nach getSchubladen
geschlossen, können die Daten einzelner Schubladen nicht mehr abgefragt werden. Hibernate wirft dann eine LazyInitializationException.
Dieses Problem löst man am besten durch eine gekapselte Sessionverwaltung, die für die Anwendung transparent eine Hibernate-Session erzeugt und diese am Leben hält.