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

당신은 얻을 것이다 empemp.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

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

또한 가져 오는 주 엔터티와 함께 ​​페칭 전략을 사용하여 엔터티 연결을 초기화 할 수 있으므로 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.