Loading...

Hibernate ORM: Eager oder Lazy Loading? Wann du welches nutzen solltest

JPA
5. Juli 2023
4 Minuten Lesezeit
Beitrag teilen:
Gefällt dir der Beitrag?
Du wirst den Newsletter lieben!

Hibernate ist ein etabliertes Object-Relational Mapping (ORM) Framework, das in der Java-Entwicklung weit verbreitet ist. Dieses Framework hilft Entwicklern, den Code für Datenbankvorgänge wie das Abrufen von Daten (auch bekannt als Fetching) zu optimieren. Die Wahl der richtigen Fetching-Strategie - Eager Loading oder Lazy Loading - ist entscheidend für die Leistungsfähigkeit deiner Anwendung. In diesem Artikel betrachten wir diese beiden Strategien und diskutieren, wann und wie du sie in deinem Spring-Data-Projekt einsetzen solltest.

Eager Loading

Eager Loading ist eine Technik, bei der alle zugehörigen Daten sofort initialisiert und abgerufen werden, wenn eine Entity geladen wird. Es ist nützlich, wenn du erwartest, dass die zugehörigen Daten in naher Zukunft benötigt werden.

@Entity
public class User {
    //...

    @OneToOne(fetch = FetchType.EAGER)
    private Profile profile;
    //...
}

In diesem Beispiel wird das Profile-Objekt sofort geladen, sobald ein User-Objekt abgerufen wird.

Vorteile des Eager Loading

  • Vorläufiges Laden: Eager Loading garantiert, dass alle benötigten Daten bereits beim Laden der Entity verfügbar sind. Dies kann nützlich sein, um die Anzahl der Datenbankanfragen zu minimieren und möglicherweise die Leistung zu verbessern.

  • Einfachheit: Es erfordert weniger Überlegungen zum Code-Design, da alles sofort geladen wird.

Nachteile des Eager Loading

  • Überflüssige Daten: Es besteht das Risiko, dass unnötige Daten geladen werden, die möglicherweise nicht benötigt werden, was zu Performanceproblemen führen kann.

  • Höherer Speicherbedarf: Da alle zugehörigen Daten auf einmal geladen werden, wird mehr Speicher benötigt, was zu Problemen bei großen Datensätzen führen kann.

Lazy Loading

Lazy Loading ist das Gegenteil von Eager Loading. Hierbei werden zugehörige Daten erst dann geladen, wenn sie tatsächlich benötigt werden. Hibernate erreicht dies durch den Einsatz von Proxy-Objekten.

@Entity
public class User {
    //...

    @OneToOne(fetch = FetchType.LAZY)
    private Profile profile;
    //...
}

In diesem Beispiel wird das Profile-Objekt erst geladen, wenn es tatsächlich verwendet wird, was die Initialisierung verzögert.

Vorteile des Lazy Loading

  • Effizienz: Da nur benötigte Daten geladen werden, können Speicher und CPU-Ressourcen effizienter genutzt werden.

  • Schnellere Initialisierung: Das Hauptobjekt kann schneller geladen werden, da nicht alle zugehörigen Daten sofort geladen werden müssen.

Nachteile des Lazy Loading

  • Mehr Datenbankanfragen: Da zugehörige Daten erst bei Bedarf geladen werden, kann dies zu einer größeren Anzahl von Datenbankanfragen führen, was die Leistung beeinträchtigen kann.

  • Hibernate-Spezifische Exceptions: Wenn du auf eine noch nicht initialisierte Sammlung oder ein noch nicht initialisiertes Objekt außerhalb einer Hibernate-Session zugreifst, kann dies zu einer LazyInitializationException führen. Durch die Einführung einer Transaction existiert implizit eine Hibernate-Session. Dies ist meist das gewünschte Verhalten.

Benutzerdefinierte Abfragen mit @Query

Eine weitere Möglichkeit, Daten zu laden, besteht darin, benutzerdefinierte Abfragen mit der @Query-Annotation zu verwenden. Dies gibt dir eine feinere Kontrolle über die Datenbankanfragen und ermöglicht es dir, spezifische Optimierungen vorzunehmen.

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    @Query("SELECT u FROM User u JOIN FETCH u.profile WHERE u.id = :id")
    User findByIdAndFetchProfileEagerly(@Param("id") Long id);
}

In diesem Beispiel wird eine benutzerdefinierte Abfrage verwendet, um das User-Objekt und sein zugehöriges Profile-Objekt in einer einzigen Datenbankanfrage zu laden.

Empfehlungen von Hibernate

Laut der offiziellen Hibernate-Dokumentation ist Lazy Loading die bevorzugte Wahl , da es die Leistung durch das Laden nur der benötigten Daten optimiert. Statt in den anderen Fällen den FetchType.EAGER statisch zu definieren, wird empfohlen auf dynamische Mechanismen wie die @Query Annotation, einem EntityGraph oder der Criteria API zurückzugreifen.

Dennoch hängt die Wahl der Fetching-Strategie stark vom spezifischen Anwendungsfall und den Anforderungen der Anwendung ab. Es ist wichtig, die Anwendung während der Entwicklung und nach dem Live-Gang zu überwachen und zu optimieren, um eine optimale Leistung zu gewährleisten.

Die Wahl der richtigen Datenabrufstrategie in Hibernate kann eine Herausforderung sein, hat aber einen signifikanten Einfluss auf die Leistung und Effizienz deiner Anwendung. Sowohl Eager Loading als auch Lazy Loading haben ihre Vor- und Nachteile, und es ist wichtig, den Kontext deiner Anwendung zu berücksichtigen, um die beste Entscheidung zu treffen. Mit benutzerdefinierten Abfragen über @Query kannst du noch mehr Kontrolle über den Datenabruf erlangen.

Kennst du schon Marcus' Backend Newsletter?

Neue Ideen. 2x pro Woche!
Top