FetchMode im Ruhezustand

1. Einleitung

In diesem kurzen Tutorial werden wir uns verschiedene FetchMode- Werte ansehen , die wir in der Annotation @ org.hibernate.annotations.Fetch verwenden können .

2. Einrichten des Beispiels

Als Beispiel verwenden wir die folgende Kundenentität mit nur zwei Eigenschaften - einer ID und einer Reihe von Aufträgen:

@Entity public class Customer { @Id @GeneratedValue private Long id; @OneToMany(mappedBy = "customer") @Fetch(value = FetchMode.SELECT) private Set orders = new HashSet(); // getters and setters }

Außerdem erstellen wir eine Auftragsentität , die aus einer ID, einem Namen und einem Verweis auf den Kunden besteht .

@Entity public class Order { @Id @GeneratedValue private Long id; private String name; @ManyToOne @JoinColumn(name = "customer_id") private Customer customer; // getters and setters }

In jedem der nächsten Abschnitte holen wir den Kunden aus der Datenbank und erhalten alle Bestellungen:

Customer customer = customerRepository.findById(id).get(); Set orders = customer.getOrders();

3. FetchMode.SELECT

In unserer Kundenentität haben wir die Eigenschaft " orders" mit einer Annotation " @Fetch" versehen :

@OneToMany @Fetch(FetchMode.SELECT) private Set orders;

Wir verwenden @Fetch, um zu beschreiben, wie Hibernate die Eigenschaft abrufen soll, wenn wir einen Kunden suchen .

Die Verwendung von SELECT gibt an, dass die Eigenschaft träge geladen werden soll.

Dies bedeutet, dass für die erste Zeile:

Customer customer = customerRepository.findById(id).get();

Wir werden keine Verknüpfung mit der Auftragstabelle sehen:

Hibernate: select ...from customer where customer0_.id=? 

Und das für die nächste Zeile:

Customer customer = customerRepository.findById(id).get();

Wir werden nachfolgende Anfragen für die zugehörigen Bestellungen sehen:

Hibernate: select ...from order where order0_.customer_id=? 

Der Ruhezustand FetchMode.SELECT generiert eine separate Abfrage für jede Bestellung , die geladen werden muss.

In unserem Beispiel gibt dies eine Abfrage zum Laden der Kunden und fünf zusätzliche Abfragen zum Laden der Auftragssammlung.

Dies ist als n + 1-Auswahlproblem bekannt. Das Ausführen einer Abfrage löst n zusätzliche Abfragen aus.

3.1. @ BatchSize

FetchMode.SELECT verfügt über eine optionale Konfigurationsanmerkung mit der Annotation @BatchSize :

@OneToMany @Fetch(FetchMode.SELECT) @BatchSize(size=10) private Set orders;

Hibernate wird versuchen , die Aufträge Sammlung in Chargen durch die definierte zu laden Größe Parameter.

In unserem Beispiel haben wir nur fünf Bestellungen, sodass eine Abfrage ausreicht.

Wir werden immer noch dieselbe Abfrage verwenden:

Hibernate: select ...from order where order0_.customer_id=?

Es wird aber nur einmal ausgeführt. Jetzt haben wir nur noch zwei Abfragen: Eine zum Laden des Kunden und eine zum Laden der Auftragssammlung.

4. FetchMode.JOIN

Während FetchMode.SELECT Beziehungen träge lädt, lädt FetchMode.JOIN sie eifrig, beispielsweise über einen Join:

@OneToMany @Fetch(FetchMode.JOIN) private Set orders;

Dies führt zu nur einer Abfrage sowohl für den Kunden als auch für seine Bestellungen :

Hibernate: select ... from customer customer0_ left outer join order order1 on customer.id=order.customer_id where customer.id=?

5. FetchMode.SUBSELECT

Da die Eigenschaft orders eine Auflistung ist, können wir auch FetchMode.SUBSELECT verwenden :

@OneToMany @Fetch(FetchMode.SUBSELECT) private Set orders;

Wir können SUBSELECT nur mit Sammlungen verwenden.

Mit diesem Setup kehren wir zu einer Abfrage für den Kunden zurück:

Hibernate: select ... from customer customer0_ 

Und eine Abfrage für die Bestellungen mit einer Unterauswahl dieses Mal:

Hibernate: select ... from order order0_ where order0_.customer_id in ( select customer0_.id from customer customer0_ )

6. FetchMode vs. FetchType

In general, FetchMode defines how Hibernate will fetch the data (by select, join or subselect). FetchType, on the other hand, defines whether Hibernate will load data eagerly or lazily.

The exact rules between these two are as follows:

  • if the code doesn't set FetchMode, the default one is JOIN and FetchType works as defined

  • with FetchMode.SELECT or FetchMode.SUBSELECT set, FetchType also works as defined
  • with FetchMode.JOIN set, FetchType is ignored and a query is always eager

For further information please refer to Eager/Lazy Loading In Hibernate.

7. Conclusion

In diesem Tutorial haben wir die verschiedenen Werte von FetchMode und ihre Beziehung zu FetchType kennengelernt .

Wie immer ist der gesamte Quellcode auf GitHub verfügbar.