Hibernate-Tipp: Wie sollten lazy geladene Beziehungen initialisiert werden?

Die Hibernate-Tipps-Serie bietet schnelle und einfache Lösungen zu verbreiteten Hibernate-Fragen. Dieses Mal geht es um die ideale Initialisierung von verzögert geladenen Beziehungen.

vorlesen Druckansicht
Lesezeit: 2 Min.
Von
  • Thorben Janssen
Inhaltsverzeichnis

Die Hibernate-Tipps-Serie bietet schnelle und einfache Lösungen zu verbreiteten Hibernate-Fragen. Dieses Mal geht es um die ideale Initialisierung von lazy geladenen Beziehungen.

Wie kann ich eine lazy geladene Beziehung beim Laden einer Entität initialisieren, um eine LazyInitializationException zu vermeiden?

Hibernate wirft immer dann eine LazyInitializationException, wenn die Elemente einer Beziehung ohne eine aktive Hibernate-Session geladen werden sollen. So wie im folgenden Beispiel:

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

Author a = em.createQuery("SELECT a FROM Author a WHERE id = 1", Author.class).getSingleResult();

em.getTransaction().commit();
em.close();

log.info(a.getFirstName()+" "+a.getLastName()+" wrote "+a.getBooks().size()+" books.");

Um dies zu verhindern, muss die Beziehung initialisiert werden, bevor die Hibernate-Session geschlossen wird. Dazu bieten JPA und Hibernate verschiedene Möglichkeiten. Die Einfachste ist eine JOIN FETCH-Klausel. Das zusätzliche Schlüsselwort FETCH teilt Hibernate mit, dass die Entitäten nicht nur für diese Abfrage verknüpft, sondern auch gemeinsam geladen werden sollen. Damit wird die Beziehung initialisiert und eine spätere LazyInitializationException verhindert.

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

Author a = em.createQuery("SELECT a FROM Author a JOIN FETCH a.books WHERE a.id = 1", Author.class).getSingleResult();

em.getTransaction().commit();
em.close();

log.info(a.getFirstName()+" "+a.getLastName()+" wrote "+a.getBooks().size()+" books.");

Die JOIN FETCH-Klausel ist nur eine der zur Verfügung stehenden Möglichkeiten um lazy geladene Beziehungen zu initialisieren. Andere Optionen sind ein @NamedEntityGraph oder ein ad-hoc erzeugter EntityGraph. Diese ermöglichen die Definition eines abfrageunabhängigen Graphen von Entitäten, die mit der Abfrage geladen werden sollen.

Alle drei Möglichkeiten verhindern nicht nur die LazyInitializationException. Mit ihnen kann auch das bekannte „n+1 Select“-Problem vermieden werden.

Mehr als 70 solcher Rezepte zu Themen wie einfache und komplexe Mapping-Definitionen, Logging, Unterstützung von Java 8, Caching sowie das statische und dynamische Erzeugen von Abfragen gibt es in meinem Buch "Hibernate Tips: More than 70 solutions to common Hibernate problems". Es ist als Taschenbuch und E-Book auf Amazon und als PDF auf hibernate-tips.com erhältlich. ()