Bitte helfen Sie mir zu verstehen, wo Sie einen regulären JOIN und wo einen JOIN FETCH verwenden können.
Zum Beispiel, wenn wir diese beiden Abfragen haben
FROM Employee emp
JOIN emp.department dep
und
FROM Employee emp
JOIN FETCH emp.department dep
Gibt es einen Unterschied zwischen ihnen? Wenn ja, welches wann?
Antworten:
In diesen beiden Abfragen verwenden Sie JOIN, um alle Mitarbeiter abzufragen, denen mindestens eine Abteilung zugeordnet ist.
Der Unterschied besteht jedoch darin, dass Sie in der ersten Abfrage nur die Mitarbeiter für den Ruhezustand zurückgeben. In der zweiten Abfrage geben Sie die Mitarbeiter und alle zugeordneten Abteilungen zurück.
Wenn Sie also die zweite Abfrage verwenden, müssen Sie keine neue Abfrage durchführen, um die Datenbank erneut aufzurufen und die Abteilungen der einzelnen Mitarbeiter anzuzeigen.
Sie können die zweite Abfrage verwenden, wenn Sie sicher sind, dass Sie die Abteilung jedes Mitarbeiters benötigen. Wenn Sie die Abteilung nicht benötigen, verwenden Sie die erste Abfrage.
Ich empfehle, diesen Link zu lesen, wenn Sie eine WHERE-Bedingung anwenden müssen (was Sie wahrscheinlich benötigen werden): Wie kann man JPQL "join fetch" mit der "where" -Klausel als JPA 2 CriteriaQuery richtig ausdrücken?
Aktualisieren
Wenn Sie nicht verwenden
fetch
und die Abteilungen weiterhin zurückgegeben werden, liegt dies daran, dass Ihre Zuordnung zwischen Mitarbeiter und Abteilung (a@OneToMany
) mit festgelegt istFetchType.EAGER
. In diesem Fall bringt jede HQL-fetch
Abfrage (mit oder nicht) mitFROM Employee
alle Abteilungen. Denken Sie daran, dass alle Zuordnungen * ToOne (@ManyToOne
und@OneToOne
) standardmäßig EAGER sind.quelle
fetch
ist, dass dies verwendet werden muss, wenn Sie (anhand unseres Beispiels) nach einem Abteilungsattribut bestellen möchten. Andernfalls (gültig zumindest für PG) könnten SieERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
In diesem Link, den ich zuvor im Kommentar erwähnt habe, lesen Sie diesen Teil:
Dieser "JOIN FETCH" hat seine Wirkung, wenn Sie die Eigenschaft (fetch = FetchType.LAZY) für eine Sammlung innerhalb einer Entität haben (Beispiel unten).
Und es ist nur die Methode "wann die Abfrage erfolgen soll". Und Sie müssen auch wissen , diese :
Wann wird die Zuordnung abgerufen -> Ihr Typ "FETCH"
wie wird es abgerufen -> Join / select / Subselect / Batch
In Ihrem Fall hat FETCH nur dann eine Wirkung, wenn Sie eine Abteilung als Set in Employee haben, etwa so in der Entität:
wenn Sie verwenden
du wirst bekommen
emp
undemp.dep
. Wenn Sie Fetch nicht verwendet haben, können Sie immer noch abrufen,emp.dep
aber der Ruhezustand verarbeitet eine weitere Auswahl in der Datenbank, um diese Abteilung zu erhalten.Es handelt sich also nur um eine Leistungsoptimierung. Sie möchten alle Ergebnisse (Sie benötigen sie oder nicht) in einer einzigen Abfrage erhalten (eifriges Abrufen) oder Sie möchten sie später abfragen, wenn Sie sie benötigen (verzögertes Abrufen).
Verwenden Sie eifriges Abrufen, wenn Sie kleine Daten mit einer Auswahl (einer großen Abfrage) abrufen möchten. Oder verwenden Sie Lazy Fetching, um abzufragen, was Sie letzteres benötigen (viele kleinere Abfragen).
Verwenden Sie fetch, wenn:
Keine große nicht benötigte Sammlung / Menge innerhalb der Entität, die Sie erhalten möchten
Kommunikation vom Anwendungsserver zum Datenbankserver zu weit und dauert lange
Möglicherweise benötigen Sie diese Sammlung, wenn Sie keinen Zugriff darauf haben ( außerhalb der Transaktionsmethode / -klasse).
quelle
List
statt eine wärenSet
?FETCH
Schlüsselworts in einer JPQL-Anweisung eine eifrig abgerufene Eigenschaft?BEITRETEN
Bei Verwendung
JOIN
für Entitätszuordnungen generiert JPA einen JOIN zwischen der übergeordneten Entität und den untergeordneten Entitätstabellen in der generierten SQL-Anweisung.Nehmen Sie also Ihr Beispiel, wenn Sie diese JPQL-Abfrage ausführen:
Hibernate generiert die folgende SQL-Anweisung:
FETCH BEITRETEN
Also, im Vergleich zu
JOIN
, dieJOIN FETCH
ermöglicht es Ihnen , die Verbindungstabellenspalten in der ProjektSELECT
Klausel der generierten SQL - Anweisung.In Ihrem Beispiel bei der Ausführung dieser JPQL-Abfrage:
Hibernate generiert die folgende SQL-Anweisung:
Dies
JOIN FETCH
ist auch eine gute Möglichkeit,LazyInitializationException
dasFetchType.LAZY
Problem bei der Verwendung des Ruhezustands zu beheben, da Sie Entitätszuordnungen mithilfe der Abrufstrategie zusammen mit der Hauptentität, die Sie abrufen, initialisieren können .quelle
Wenn Sie die
@oneToOne
Zuordnung auf festgelegt habenFetchType.LAZY
und eine zweite Abfrage verwenden (da Abteilungsobjekte als Teil von Mitarbeiterobjekten geladen werden müssen), werden im Ruhezustand Abfragen ausgeführt, um Abteilungsobjekte für jedes einzelne Mitarbeiterobjekt abzurufen, das aus der Datenbank abgerufen wird.Später im Code können Sie über die einwertige Zuordnung von Mitarbeiter zu Abteilung auf Abteilungsobjekte zugreifen, und der Ruhezustand gibt keine Abfrage zum Abrufen des Abteilungsobjekts für den angegebenen Mitarbeiter aus.
Denken Sie daran, dass Hibernate weiterhin Abfragen ausgibt, die der Anzahl der abgerufenen Mitarbeiter entsprechen. Der Ruhezustand gibt in beiden oben genannten Abfragen die gleiche Anzahl von Abfragen aus, wenn Sie auf Abteilungsobjekte aller Mitarbeiterobjekte zugreifen möchten
quelle
Dherik: Ich bin mir nicht sicher, was Sie sagen. Wenn Sie Fetch nicht verwenden, ist das Ergebnis vom Typ: Dies
List<Object[ ]>
bedeutet eine Liste von Objekttabellen und keine Liste von Mitarbeitern.Wenn Sie Fetch verwenden, gibt es nur eine Auswahl und das Ergebnis ist die Liste der Mitarbeiter,
List<Employee>
die die Liste der Abteilungen enthält. Es überschreibt die verzögerte Deklaration der Entität.quelle
fetch
, gibt Ihre Abfrage nur die Mitarbeiter zurück. Wenn die Abteilungen auch in diesem Fall weiterhin zurückgegeben werden, liegt dies daran, dass Ihre Zuordnung zwischen Mitarbeiter und Abteilung (ein @OneToMany) mit FetchType.EAGER festgelegt wurde. In diesem Fall bringt jede HQL-fetch
Abfrage (mit oder nicht) mitFROM Employee
alle Abteilungen.@OneToMany(fetch = FetchType.EAGER
) ist. Ist dies nicht der Fall, werden die Abteilungen nicht zurückgesandt.select
in der HQL gemacht wurde. Versuchen Sie esSELECT emp FROM Employee emp JOIN FETCH emp.department dep
. JPA / Hibernate haben dieses Verhalten der Rückkehr eineList
der ,Object[]
wenn Sie den ommitSELECT
Teil.