문제에 대한 설명
위에서 말했듯이 LazyCollectionOption.EXTRA 주석에는 문제가 있습니다. 각 개체에 대해 데이터베이스에 별도의 요청을 수행합니다. 우리는 부모 객체에 대한 모든 자식 객체를 즉시 로드하기를 원한다고 Hibernate에 어떻게든 설명할 필요가 있습니다.
Hibernate의 개발자들은 이 문제에 대한 해결책인 HQL의 조인 인출 연산자 를 제시했습니다 .
HQL 쿼리 예:
select distinct task from Task t left join fetch t.employee order by t.deadline
이 쿼리에서는 모든 것이 동시에 단순하면서도 복잡합니다. 하나씩 구성해 보도록 하겠습니다.
옵션 1
모든 개체를 다운로드하고 싶습니다.일, 기한순으로 정렬됩니다. 해당 요청은 다음과 같습니다.
select task from Task t order by t.deadline
모든 것이 명확하지만. 그러나 현장직원Task 클래스 의 EXTRA 주석 으로 주석이 달린 직원 모음이 포함됩니다 . 그리고 이 컬렉션의 개체는 로드되지 않습니다.
옵션 2
Hibernate가 객체에 대한 하위 객체를 로드하도록 강제일.
select task from Task t join fetch t.employee order by t.deadline
도움을 받아 쿼리에서 Task 및 Employee 엔터티를 명시적으로 바인딩합니다. Hibernate는 이러한 필드에 @ManyToMany 주석을 사용하기 때문에 이미 이것을 알고 있습니다 .
그러나 조인 페치를 얻기 위해 페치 문 으로 완료하려면 조인 문이 필요합니다 . 이것이 우리의 요청이 실행될 때 Task.employee 컬렉션의 객체가 데이터베이스에서 로드되어야 한다고 Hibernate에 알리는 방법입니다.
옵션 3
이전 솔루션에는 몇 가지 버그가 있습니다. 첫째, 조인을 사용한 후 SQL은 개체를 반환하지 않습니다.일, Employee 테이블에 연결된 개체가 없습니다. 이것이 바로 내부 조인이 작동하는 방식입니다 .
따라서 왼쪽 연산자 로 조인을 보강 하고 이를 왼쪽 조인 으로 전환 해야 합니다 . 예:
select task from Task t left join fetch t.employee order by t.deadline
옵션 4
하지만 그게 다가 아닙니다. 코드에서 엔터티 간의 관계가 다대일인 경우 쿼리 결과에 중복 항목이 있습니다. 같은 개체일다른 직원(Employee 개체)에서 찾을 수 있습니다.
따라서 중복 작업 개체를 제거하려면 선택 단어 뒤에 고유 키워드를 추가해야 합니다.
select distinct task from Task t left join fetch t.employee order by t.deadline
이것이 우리가 시작한 요청에 도달한 4단계의 방법입니다. 글쎄요, Java 코드는 예상대로 보일 것입니다.
String hql = " select distinct task from Task t left join fetch t.employee order by t.deadline";
Query<Task> query = session.createQuery( hql, Task.class);
return query.list();
JOIN FETCH 제한 사항
누구도 완벽하지 않다. JOIN FETCH 문도 마찬가지입니다. 그것은 꽤 많은 제한이 있습니다. 첫 번째는 setMaxResults() 및 setFirstResult() 메서드를 사용하는 것입니다 .
JOIN FETCH 문의 경우 Hibernate는 직원, 작업 및 직원 작업의 세 테이블을 하나로 결합하는 매우 복잡한 쿼리를 생성합니다. 실제로 이것은 직원이나 작업에 대한 요청이 아니라 알려진 모든 직원-작업 쌍에 대한 요청입니다.
그리고 SQL은 LIMIT 및 OFFSET 문을 직원-태스크 쌍의 쿼리에 정확히 적용할 수 있습니다. 동시에 HQL 쿼리에서 우리가 정확히 작업(Task)을 가져오길 원하고 FirstResult 및 MaxResult 매개변수를 재배포하는 경우 구체적으로 Task 개체를 참조해야 한다는 것이 분명합니다.
다음과 같이 코드를 작성하는 경우:
String hql = " select distinct task from Task t left join fetch t.employee order by t.deadline";
Query<Task> query = session.createQuery( hql, Task.class);
query.setFirstResult(0);
query.setMaxResults(1);
return query.list();
그런 다음 Hibernate는 FirstResult 및 MaxResult를 SQL 쿼리의 OFFSET 및 LIMIT 매개변수로 올바르게 변환할 수 없습니다.
대신 다음 세 가지 작업을 수행합니다.
- SQL 쿼리는 일반적으로 테이블에서 모든 데이터를 선택하고 Hibernate로 반환합니다.
- 최대 절전 모드는 메모리에서 필요한 레코드를 선택하여 사용자에게 반환합니다.
- 최대 절전 모드는 경고를 발행합니다
경고는 다음과 같습니다.
WARN [org.hibernate.hql.internal.ast.QueryTranslatorImpl] HHH000104:
firstResult/maxResults specified with collection fetch; applying in memory!
GO TO FULL VERSION