정규 JOIN 사용 위치와 JOIN FETCH 위치를 이해하도록 도와주세요.
예를 들어이 두 쿼리가
FROM Employee emp
JOIN emp.department dep
과
FROM Employee emp
JOIN FETCH emp.department dep
그들 사이에 차이점이 있습니까? 그렇다면 어느 것을 사용해야합니까?
정규 JOIN 사용 위치와 JOIN FETCH 위치를 이해하도록 도와주세요.
예를 들어이 두 쿼리가
FROM Employee emp
JOIN emp.department dep
과
FROM Employee emp
JOIN FETCH emp.department dep
그들 사이에 차이점이 있습니까? 그렇다면 어느 것을 사용해야합니까?
답변:
이 두 쿼리에서는 JOIN을 사용하여 하나 이상의 부서가 연결된 모든 직원을 쿼리합니다.
그러나 차이점은 첫 번째 쿼리에서 최대 절전 모드에 대한 고용 만 반환한다는 것입니다. 두 번째 쿼리에서는 고용 및 관련 부서를 모두 반환합니다 .
따라서 두 번째 쿼리를 사용하는 경우 데이터베이스를 다시 방문하여 각 직원의 부서를 확인하기 위해 새 쿼리를 수행 할 필요가 없습니다.
각 직원의 부서가 필요할 때 두 번째 쿼리를 사용할 수 있습니다. 부서가 필요하지 않은 경우 첫 번째 쿼리를 사용하십시오.
WHERE 조건을 적용 해야하는 경우이 링크를 읽으십시오 (필요한 것) : JPQL "join fetch"를 "where"절과 함께 JPA 2 CriteriaQuery로 올바르게 표현하는 방법 은 무엇 입니까?
최신 정보
사용하지 않고 fetch
부서가 계속 반환되는 경우 Employee와 Department (a @OneToMany
) 간의 매핑이로 설정되어 있기 때문 입니다 FetchType.EAGER
. 이 경우 모든 HQL fetch
쿼리가 있거나없는 쿼리가 FROM Employee
모든 부서를 가져옵니다. 모든 맵핑 * ToOne ( @ManyToOne
및 @OneToOne
)은 기본적으로 EAGER 입니다.
fetch
(우리의 예를 사용하는) 경우에 사용하는 당신은 일부학과의 특성에 의한 주문합니다. 그렇지 않으면, (유효 PG에 대한 최소한) 당신은 얻을 수 있습니다ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
에서 이 링크 내가 주석에 앞서 언급,이 부분을 읽어
"페치"조인을 사용하면 단일 선택을 사용하여 연관 또는 값의 콜렉션을 상위 오브젝트와 함께 초기화 할 수 있습니다. 이것은 컬렉션의 경우에 특히 유용합니다. 연관 및 콜렉션에 대한 맵핑 파일의 외부 결합 및 지연 선언을 효과적으로 대체합니다 .
이 "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에 대한 액세스 권한이 없을 때 당신은 후자 해당 모음을해야 할 수도 있습니다 외부 의 트랜잭션 방법 / 클래스)
List
대신 부서 인 경우 부서를 계속해서 가져 오겠습니까 Set
?
FETCH
JPQL 문에서 키워드를 사용하면 열성적으로 검색된 속성을 의미합니까?
사용할 때 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
.
그래서, 비교 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
는FROM
JPQL 절에 나열된 엔티티와 연관된 컬럼뿐만 아니라 테이블 컬럼도 선택됩니다 .
또한 가져 오는 주 엔터티와 함께 페칭 전략을 사용하여 엔터티 연결을 초기화 할 수 있으므로 Hibernate를 사용할 때 문제 JOIN FETCH
를 해결하는 좋은 방법 입니다.LazyInitializationException
FetchType.LAZY
당신이있는 경우 @oneToOne
에 매핑 설정을 FetchType.LAZY
하고 무엇 Hibernate는 할 것 (당신이 부서 직원의 일부 객체로로드 할 객체를 필요로하기 때문에) 당신이 두 번째 쿼리를 사용하여,이 부서는 DB에서 가져 오는 모든 개별 직원 개체에 대한 개체를 가져 오기 위해 쿼리를 발행합니다.
나중에 코드에서 Employee to Department 단일 값 연결을 통해 Department 객체에 액세스 할 수 있으며 Hibernate는 지정된 Employee에 대한 Department 객체를 가져 오기 위해 쿼리를 발행하지 않습니다.
Hibernate는 여전히 가져온 직원 수와 동일한 쿼리를 발행합니다. 모든 Employee 객체의 Department 객체에 액세스하려는 경우 Hibernate는 위의 두 쿼리에서 동일한 수의 쿼리를 발행합니다.
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
모든 부서를 가져옵니다.
@OneToMany(fetch = FetchType.EAGER
) 인 경우에만 발생합니다 . 그렇지 않은 경우 부서는 반환되지 않습니다.
select
HQL에서 작성된 방식입니다. 시도하십시오 SELECT emp FROM Employee emp JOIN FETCH emp.department dep
. JPA / Hibernate는 부품 을 생략 할 때 a List
의 리턴 동작을 갖습니다 . Object[]
SELECT