JPA와 Hibernate를 사용할 때 JOIN과 JOIN FETCH의 차이점은 무엇입니까?


183

정규 JOIN 사용 위치와 JOIN FETCH 위치를 이해하도록 도와주세요.

예를 들어이 두 쿼리가

FROM Employee emp
JOIN emp.department dep

과

FROM Employee emp
JOIN FETCH emp.department dep

그들 사이에 차이점이 있습니까? 그렇다면 어느 것을 사용해야합니까?


2
당신은 여기에서 찾을 수 있습니다 링크 읽을 14.3. 협회 및 회원
— Angga

4
나는 그 문서화를 겪었지만 여전히 JOIN을 사용해야하는 곳과 JOIN FETCH를 모릅니다.
— abbas

2
@oneToOne 매핑이 FetchType.LAZY로 설정되어 있고 Hibernate가 수행 할 부서 오브젝트를 Employee 오브젝트의 일부로로드해야하기 때문에 두 번째 쿼리를 사용하는 경우, 모든 개별 Employee 오브젝트에 대해 Department 오브젝트를 페치하기 위해 쿼리를 발행합니다. DB에서 가져옵니다. 나중에 코드에서 Employee to Department 단일 값 연결을 통해 Department 객체에 액세스 할 수 있으며 Hibernate는 지정된 Employee에 대한 Department 객체를 가져 오기 위해 쿼리를 발행하지 않습니다. 최대 절전 모드는 여전히 가져온 직원 수와 동일한 쿼리를 발행합니다.
— Bunti

문서 사냥 ~ Fetching Strategies
— Eddie B

1
@ShameeraAnuranga이 경우에는 LEFT OUTER JOIN이 필요하다고 생각합니다.
— abbas

답변:


181

이 두 쿼리에서는 JOIN을 사용하여 하나 이상의 부서가 연결된 모든 직원을 쿼리합니다.

그러나 차이점은 첫 번째 쿼리에서 최대 절전 모드에 대한 고용 만 반환한다는 것입니다. 두 번째 쿼리에서는 고용 및 관련 부서를 모두 반환합니다 .

따라서 두 번째 쿼리를 사용하는 경우 데이터베이스를 다시 방문하여 각 직원의 부서를 확인하기 위해 새 쿼리를 수행 할 필요가 없습니다.

각 직원의 부서가 필요할 때 두 번째 쿼리를 사용할 수 있습니다. 부서가 필요하지 않은 경우 첫 번째 쿼리를 사용하십시오.

WHERE 조건을 적용 해야하는 경우이 링크를 읽으십시오 (필요한 것) : JPQL "join fetch"를 "where"절과 함께 JPA 2 CriteriaQuery로 올바르게 표현하는 방법 은 무엇 입니까?

최신 정보

사용하지 않고 fetch부서가 계속 반환되는 경우 Employee와 Department (a @OneToMany) 간의 매핑이로 설정되어 있기 때문 입니다 FetchType.EAGER. 이 경우 모든 HQL fetch쿼리가 있거나없는 쿼리가 FROM Employee모든 부서를 가져옵니다. 모든 맵핑 * ToOne ( @ManyToOne및 @OneToOne)은 기본적으로 EAGER 입니다.


1
가져 오기없이 명령문을 실행하고 결과를 얻으면 어떤 동작이 수행됩니까? 그럼 세션 내에서 우리는 부서로 취급할까요?
— gstackoverflow 10

1
@gstackoverflow, yes
— Dherik

관계의 양쪽에서 지연 가져 오기와 함께 원시 쿼리를 사용하지만 여전히 하위 관계의 계층 구조를로드합니다.
— Badamchi

그 가치가 언급 fetch (우리의 예를 사용하는) 경우에 사용하는 당신은 일부학과의 특성에 의한 주문합니다. 그렇지 않으면, (유효 PG에 대한 최소한) 당신은 얻을 수 있습니다ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
— 긴

60

에서 이 링크 내가 주석에 앞서 언급,이 부분을 읽어

"페치"조인을 사용하면 단일 선택을 사용하여 연관 또는 값의 콜렉션을 상위 오브젝트와 함께 초기화 할 수 있습니다. 이것은 컬렉션의 경우에 특히 유용합니다. 연관 및 콜렉션에 대한 맵핑 파일의 외부 결합 및 지연 선언을 효과적으로 대체합니다 .

이 "JOIN FETCH"는 엔터티 내부의 컬렉션에 대해 (fetch = FetchType.LAZY) 속성이있는 경우 효과가 있습니다 (예 : 아래).

그리고 "쿼리가 발생할 때"의 방법에만 영향을 미칩니다. 그리고 당신도 이것을 알아야 합니다 :

최대 절전 모드에는 두 가지 직교 개념이 있습니다. 연결은 언제 가져오고 어떻게 가져 옵니까? 혼동하지 않는 것이 중요합니다. 가져 오기를 사용하여 성능을 조정합니다. 지연을 사용하여 특정 클래스의 분리 된 인스턴스에서 항상 사용 가능한 데이터에 대한 계약을 정의 할 수 있습니다.

연결이 언제 페치되는지-> "FETCH"유형

어떻게 가져 오는가-> Join / select / Subselect / Batch

귀하의 경우 FETCH는 직원 내부에 부서로 부서가있는 경우에만 효과가 있습니다.

@OneToMany(fetch = FetchType.LAZY)
private Set<Department> department;

당신이 사용할 때

FROM Employee emp
JOIN FETCH emp.department dep

당신은 얻을 것이다 emp 및 emp.dep. 페치를 사용하지 않아도 여전히 얻을 수는 emp.dep있지만 최대 절전 모드는 데이터베이스에 대한 다른 선택을 처리하여 해당 부서 세트를 가져옵니다.

따라서 성능 조정의 문제, 단일 쿼리 (열심 한 페칭)로 모든 결과를 얻거나 (필요한지 여부) 원하는 경우 후자의 쿼리를 원합니다 (지연 페치).

한 번의 select (하나의 큰 쿼리)로 작은 데이터를 가져와야 할 경우 열성적인 페칭을 사용하십시오. 또는 lazy fetching을 사용하여 후자에 필요한 것을 쿼리하십시오 (많은 더 작은 쿼리).

다음과 같은 경우 인출을 사용하십시오.

  • 당신이 얻으려고하는 엔티티 내부에 큰 불필요한 수집 / 세트가 없습니다.

  • 응용 프로그램 서버에서 데이터베이스 서버로의 통신이 너무 길고 오랜 시간이 필요함

  • 당신은 (는 IT에 대한 액세스 권한이 없을 때 당신은 후자 해당 모음을해야 할 수도 있습니다 외부 의 트랜잭션 방법 / 클래스)


방금 업데이트 된 질문에 쓴 쿼리에 대해 설명해 주시겠습니까?
— abbas

유용한 고려 사항 : "당신이 얻을려고하는 그 엔티티 내부에 큰 불필요한 수집 / 설정이 없습니다"
— Divs

직원 내부의 부서가 List대신 부서 인 경우 부서를 계속해서 가져 오겠습니까 Set?
— 스테판

FETCHJPQL 문에서 키워드를 사용하면 열성적으로 검색된 속성을 의미합니까?
— 스테판

15

붙다

사용할 때 JOIN엔티티 연관에 대해 하는 경우 JPA는 생성 된 SQL 문에서 상위 엔티티와 하위 엔티티 테이블간에 JOIN을 생성합니다.

따라서이 JPQL 쿼리를 실행할 때 예를 들어보십시오.

FROM Employee emp
JOIN emp.department dep

최대 절전 모드는 다음 SQL 문을 생성합니다.

SELECT emp.*
FROM employee emp
JOIN department dep ON emp.department_id = dep.id

SQL SELECT절은 employee테이블 열만 포함하고 테이블 열 은 포함 하지 않습니다 department. department테이블 열 을 가져 오려면 JOIN FETCH대신 대신 사용해야 합니다 JOIN.

FETCH 가입

그래서, 비교 JOIN의는 JOIN FETCH당신이에 가입 테이블 열을 투사 할 수 있습니다 SELECT생성 된 SQL 문 절.

따라서 귀하의 예 에서이 JPQL 쿼리를 실행할 때 :

FROM Employee emp
JOIN FETCH emp.department dep

최대 절전 모드는 다음 SQL 문을 생성합니다.

SELECT emp.*, dept.*
FROM employee emp
JOIN department dep ON emp.department_id = dep.id

이번에 department는 FROMJPQL 절에 나열된 엔티티와 연관된 컬럼뿐만 아니라 테이블 컬럼도 선택됩니다 .

또한 가져 오는 주 엔터티와 함께 ​​페칭 전략을 사용하여 엔터티 연결을 초기화 할 수 있으므로 Hibernate를 사용할 때 문제 JOIN FETCH를 해결하는 좋은 방법 입니다.LazyInitializationExceptionFetchType.LAZY


동일한 쿼리에서 여러 JOIN FETCH를 사용할 수 있습니까?
— A.Onur Özcan

2
여러 다 대일 및 일대일 연관 및 최대 하나의 콜렉션을 FETCH에 참여할 수 있습니다. 일대 다 또는 다 대다 연관과 같은 여러 콜렉션을 가져 오면 카티 전 곱이 됩니다. 그러나 여러 컬렉션을 가져 오려면 두 번째, 세 번째, ..., n 번째 컬렉션에 보조 쿼리를 사용할 수 있습니다. 확인 이 문서 자세한 내용을.
— Vlad Mihalcea

5

당신이있는 경우 @oneToOne에 매핑 설정을 FetchType.LAZY하고 무엇 Hibernate는 할 것 (당신이 부서 직원의 일부 객체로로드 할 객체를 필요로하기 때문에) 당신이 두 번째 쿼리를 사용하여,이 부서는 DB에서 가져 오는 모든 개별 직원 개체에 대한 개체를 가져 오기 위해 쿼리를 발행합니다.

나중에 코드에서 Employee to Department 단일 값 연결을 통해 Department 객체에 액세스 할 수 있으며 Hibernate는 지정된 Employee에 대한 Department 객체를 가져 오기 위해 쿼리를 발행하지 않습니다.

Hibernate는 여전히 가져온 직원 수와 동일한 쿼리를 발행합니다. 모든 Employee 객체의 Department 객체에 액세스하려는 경우 Hibernate는 위의 두 쿼리에서 동일한 수의 쿼리를 발행합니다.


2

Dherik : fetch를 사용하지 않을 때 결과는 다음과 같은 유형이됩니다. List<Object[ ]>이는 직원 목록이 아닌 Object 테이블 목록을 의미합니다.

Object[0] refers an Employee entity 
Object[1] refers a Departement entity 

가져 오기를 사용하는 경우 하나의 선택 만 있고 결과는 List<Employee>부서 목록을 포함하는 직원 목록입니다. 엔티티의 지연 선언을 대체합니다.


당신의 관심사를 이해하는지 모르겠습니다. 를 사용하지 않으면 fetch쿼리는 직원 만 반환합니다. Departments가이 경우에도 계속 반환되는 경우 Employee와 Department (@OneToMany) 간의 매핑이 FetchType.EAGER로 설정되어 있기 때문입니다. 이 경우 모든 HQL fetch쿼리가 있거나없는 쿼리가 FROM Employee모든 부서를 가져옵니다.
— Dherik

가져 오기 (조인 만)를 사용하지 않으면 결과는 두 개의 행으로 구성된 콜렉션의 배열이며, 첫 번째는 직원의 콜렉션이고 두 번째는 부서의 콜렉션입니다. 열성적인 가져 오기 또는 지연된 가져 오기를 사용하여 부서를 가져옵니다.
— Bilal BBB

HQL에서 가져 오지 않으면 직원과 부서 간의 매핑이 EAGER ( @OneToMany(fetch = FetchType.EAGER) 인 경우에만 발생합니다 . 그렇지 않은 경우 부서는 반환되지 않습니다.
— Dherik

@Dherik은 직접 시도해보십시오 .ClassCastException이 발생합니다.
— Bilal BBB

나는 문제를 알아 낸다. 가져 오기 문제점이 아니라 selectHQL에서 작성된 방식입니다. 시도하십시오 SELECT emp FROM Employee emp JOIN FETCH emp.department dep. JPA / Hibernate는 부품 을 생략 할 때 a List의 리턴 동작을 갖습니다 . Object[]SELECT
— Dherik
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.