Proszę, pomóż mi zrozumieć, gdzie używać zwykłego JOIN, a gdzie JOIN FETCH.
Na przykład, jeśli mamy te dwa zapytania
FROM Employee emp
JOIN emp.department dep
i
FROM Employee emp
JOIN FETCH emp.department dep
Czy jest między nimi jakaś różnica? Jeśli tak, którego użyć kiedy?
Odpowiedzi:
W tych dwóch zapytaniach używasz JOIN do wysyłania zapytań do wszystkich pracowników, z którymi powiązany jest co najmniej jeden dział.
Ale różnica polega na tym, że w pierwszym zapytaniu zwracasz tylko Pracowników dla hibernacji. W drugim zapytaniu zwracasz pracowników i wszystkie powiązane działy.
Tak więc, jeśli użyjesz drugiego zapytania, nie będziesz musiał wykonywać nowego zapytania, aby ponownie trafić do bazy danych i zobaczyć działy każdego pracownika.
Możesz użyć drugiego zapytania, gdy jesteś pewien, że będziesz potrzebować działu każdego pracownika. Jeśli nie potrzebujesz działu, użyj pierwszego zapytania.
Polecam przeczytać ten link, jeśli chcesz zastosować warunek WHERE (co prawdopodobnie będziesz potrzebować): Jak poprawnie wyrazić JPQL "pobieranie złączenia" z klauzulą "gdzie" jako Kryteria zapytania JPA 2?
Aktualizacja
Jeśli nie używasz,
fetch
a działy nadal są zwracane, jest to spowodowane ustawieniem mapowania między pracownikiem a działem (a@OneToMany
)FetchType.EAGER
. W takim przypadku każdefetch
zapytanie HQL (z lub nie) zFROM Employee
przyniesie wszystkie działy. Pamiętaj, że wszystkie mapowania * ToOne (@ManyToOne
i@OneToOne
) są domyślnie EAGER.źródło
fetch
należy tego użyć, jeśli (w naszym przykładzie) chcesz zamówić według jakiegoś atrybutu działu. W przeciwnym razie (ważne przynajmniej dla PG) możesz dostaćERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
w tym linku wspomniałem wcześniej w komentarzu, przeczytaj tę część:
to "JOIN FETCH" będzie miało skutek, jeśli masz (fetch = FetchType.LAZY) właściwość dla kolekcji wewnątrz encji (przykład poniżej).
I ma to wpływ tylko na metodę „kiedy zapytanie powinno się wydarzyć”. Musisz też wiedzieć, że :
kiedy jest pobierane skojarzenie -> Twój typ „FETCH”
jak jest pobierany -> Dołącz / wybierz / Subselect / Batch
W twoim przypadku FETCH odniesie skutek tylko wtedy, gdy masz dział jako zestaw wewnątrz pracownika, coś takiego w encji:
kiedy używasz
dostaniesz
emp
iemp.dep
. jeśli nie użyłeś pobierania, nadal możesz uzyskać,emp.dep
ale hibernacja przetwarza kolejny wybór do bazy danych, aby uzyskać ten zestaw działu.więc jest to tylko kwestia dostrojenia wydajności, o tym, że chcesz uzyskać wszystkie wyniki (potrzebujesz tego lub nie) w jednym zapytaniu (pobierające chętnie) lub chcesz zapytać je później, kiedy ich potrzebujesz (pobieranie z opóźnieniem).
Korzystaj z szybkiego pobierania, gdy chcesz uzyskać małe dane za pomocą jednego wyboru (jedno duże zapytanie). Lub użyj leniwego pobierania, aby zapytać o to, czego potrzebujesz (wiele mniejszych zapytań).
użyj pobierania, gdy:
nie ma dużej niepotrzebnej kolekcji / zestawu wewnątrz tej jednostki, którą masz zamiar dostać
komunikacja z serwera aplikacji do serwera bazy danych jest za daleko i zajmuje dużo czasu
Może trzeba, że zbiór ten ostatni, gdy nie masz dostępu do niego ( poza o transakcyjnej metody / klasy)
źródło
List
zamiast aSet
?FETCH
słowa kluczowego w instrukcji JPQL oznacza chętnie pobieraną właściwość?PRZYSTĄP
W przypadku korzystania
JOIN
z powiązań jednostek JPA wygeneruje JOIN między jednostką nadrzędną a tabelami jednostek podrzędnych w wygenerowanej instrukcji SQL.Na przykład, wykonując to zapytanie JPQL:
Hibernate wygeneruje następującą instrukcję SQL:
DOŁĄCZ DO FETCH
Tak więc, w porównaniu z
JOIN
,JOIN FETCH
pozwala na rzutowanie kolumn tabeli łączącej wSELECT
klauzuli wygenerowanej instrukcji SQL.Tak więc, w twoim przykładzie, podczas wykonywania tego zapytania JPQL:
Hibernate wygeneruje następującą instrukcję SQL:
Ponadto,
JOIN FETCH
jest to świetny sposób, aby zająć sięLazyInitializationException
przy użyciu Hibernate jak można zainicjować skojarzenia obiektu przy użyciuFetchType.LAZY
strategii pobierania wraz z głównym podmiotem pobierasz.źródło
Jeśli masz
@oneToOne
ustawione mapowanieFetchType.LAZY
i używasz drugiego zapytania (ponieważ chcesz, aby obiekty działu były ładowane jako część obiektów pracownika), to, co zrobi Hibernate, to wysyła zapytania w celu pobrania obiektów działu dla każdego pojedynczego obiektu pracownika, który pobiera z DB.Później w kodzie można uzyskać dostęp do obiektów działu za pośrednictwem jednowartościowego powiązania pracownika z działem, a Hibernate nie wysyła żadnego zapytania w celu pobrania obiektu działu dla danego pracownika.
Pamiętaj, że Hibernate nadal wysyła zapytania równe liczbie pobranych pracowników. Hibernate wyśle taką samą liczbę zapytań w obu powyższych zapytaniach, jeśli chcesz uzyskać dostęp do obiektów działu wszystkich obiektów pracownika
źródło
Dherik: Nie jestem pewien, co mówisz, kiedy nie używasz funkcji pobierania, wynik będzie typu:
List<Object[ ]>
co oznacza listę tabel obiektów, a nie listę pracowników.Kiedy używasz fetch, jest tylko jeden wybór, a wynikiem jest lista Pracownik
List<Employee>
zawierająca listę działów. Zastępuje leniwą deklarację jednostki.źródło
fetch
, twoje zapytanie zwróci tylko pracowników. Jeśli działy, nawet w tym przypadku, są nadal zwracane, to dlatego, że mapowanie między pracownikiem a działem (a @OneToMany) jest ustawione za pomocą FetchType.EAGER. W takim przypadku każdefetch
zapytanie HQL (z lub nie) zFROM Employee
przyniesie wszystkie działy.@OneToMany(fetch = FetchType.EAGER
). Jeśli tak nie jest, Działy nie zostaną zwrócone.select
został wykonany w HQL. SpróbujSELECT emp FROM Employee emp JOIN FETCH emp.department dep
. JPA / Hibernate mają takie zachowanie, że zwraca wartośćList
of,Object[]
gdy pominieszSELECT
część.