JPQL JOIN 들이 헷갈리는 부분이 있어서 정리해보았습니다.
JPQL 에는 총 4 가지 JOIN 방식이 존재합니다. 그리고 이 JOIN 방식에 따라 영속성 컨텍스트로의 로딩 전략이 달라집니다.
JPQL 에서 JOIN 을 사용하려면 연관관계를 엔티티에 설정해주어야만 합니다. 그렇지 않다면 Theta Join 을 사용해야합니다.
Theta Join 은 Cartesian Product 로 곱 조인을 수행하게 됩니다. LEFT 나 INNER 조인을 수행하지 못합니다.
먼저 아래의 예제와 여러 상황을 함께 볼까요?
SELECT o FROM Order o {JOIN 형태} o.customer c WHERE c.name = 'John'
- Order 가 Customer 을 LAZY 전략으로 fetch 하고, customer 가 null 이 아닐 때
- JOIN (INNER JOIN) : Order 만 영속성 컨텍스트에 로딩됩니다.
- JOIN FETCH (INNER JOIN FETCH) : Order 와 Customer 가 영속성 컨텍스트에 로딩됩니다.
- LEFT JOIN (LEFT OUTER JOIN) : Order 만 영속성 컨텍스트에 로딩됩니다.
- LEFT JOIN FETCH (LEFT OUTER JOIN FETCH) : Order 와 Customer 가 영속성 컨텍스트에 로딩됩니다.
- Order 가 Customer 을 LAZY 전략으로 fetch 하고, customer 가 null 일 때
- JOIN (INNER JOIN) : Order 만 영속성 컨텍스트에 로딩됩니다.
- JOIN FETCH (INNER JOIN FETCH) : 아무것도 로딩되지 않습니다.
- LEFT JOIN (LEFT OUTER JOIN) : Order 만 영속성 컨텍스트에 로딩됩니다.
- LEFT JOIN FETCH (LEFT OUTER JOIN FETCH) : Order 만 영속성 컨텍스트에 로딩됩니다.
- Order 가 Customer 을 EAGER 전략으로 fetch 하고, customer 가 null 이 아닐 때
- JOIN (INNER JOIN) : Order 와 Customer 가 영속성 컨텍스트에 로딩됩니다.
- JOIN FETCH (INNER JOIN FETCH) : Order 와 Customer 가 영속성 컨텍스트에 로딩됩니다.
- LEFT JOIN (LEFT OUTER JOIN) : Order 와 Customer 가 영속성 컨텍스트에 로딩됩니다.
- LEFT JOIN FETCH (LEFT OUTER JOIN FETCH) : Order 와 Customer 가 영속성 컨텍스트에 로딩됩니다.
- Order 가 Customer 을 EAGER 전략으로 fetch 하고, customer 가 null 일 때
- JOIN (INNER JOIN) : 아무것도 로딩되지 않습니다.
- JOIN FETCH (INNER JOIN FETCH) : 아무것도 로딩되지 않습니다.
- LEFT JOIN (LEFT OUTER JOIN) : Order 만 영속성 컨텍스트에 로딩됩니다.
- LEFT JOIN FETCH (LEFT OUTER JOIN FETCH) : Order 만 영속성 컨텍스트에 로딩됩니다.
예제를 보면서 아래의 각 JOIN 별 설명을 확인한다면 더욱 빠르게 이해될거에요!
- JOIN (INNER JOIN):
- 목적: 연관된 엔티티를 조인하기 위함입니다. 주로 쿼리의 WHERE 절이나 SELECT 절에서 추가 정보를 필요로 할 때 사용됩니다.
- 로딩 전략: 해당 엔티티의 로딩 전략 (Lazy 또는 Eager)에 따라 연관된 엔티티를 로드합니다.
- 결과: 조인 조건에 맞지 않는 기본 엔티티는 결과에서 제외됩니다.
- JOIN FETCH (INNER JOIN FETCH):
- 목적: 연관된 엔티티를 즉시 로딩하기 위한 목적입니다.
- 로딩 전략: 연관된 엔티티를 강제로 즉시 로드합니다.
- 결과: 조인 조건에 맞지 않는 기본 엔티티는 결과에서 제외됩니다.
- LEFT JOIN (LEFT OUTER JOIN):
- 목적: 기본 엔티티와 연관된 엔티티를 조인하기 위한 목적입니다. 연관된 엔티티가 없더라도 기본 엔티티는 결과에 포함됩니다.
- 로딩 전략: 해당 엔티티의 로딩 전략 (Lazy 또는 Eager)에 따라 연관된 엔티티를 로드합니다.
- 결과: 기본 엔티티는 항상 결과에 포함됩니다. 연관된 엔티티가 없으면 null로 처리됩니다.
- LEFT JOIN FETCH (LEFT OUTER JOIN FETCH):
- 목적: 기본 엔티티와 연관된 엔티티를 함께 즉시 로딩하는 것이 목적입니다.
- 로딩 전략: 연관된 엔티티를 강제로 즉시 로드합니다.
- 결과: 기본 엔티티는 항상 결과에 포함됩니다. 연관된 엔티티가 없으면 null로 처리됩니다.
I organized this because JPQL JOINs were confusing.
JPQL has a total of four JOIN methods. The loading strategy into the persistence context changes depending on the JOIN method.
To use JOIN in JPQL, relationships must be configured on the entities. Otherwise, you need to use Theta Join.
Theta Join performs a Cartesian Product, or cross join. It cannot perform LEFT or INNER joins.
First, let us look at the example and several situations below.
SELECT o FROM Order o {JOIN type} o.customer c WHERE c.name = 'John'
- When Order fetches Customer with the LAZY strategy, and customer is not null
- JOIN (INNER JOIN): only Order is loaded into the persistence context.
- JOIN FETCH (INNER JOIN FETCH): Order and Customer are loaded into the persistence context.
- LEFT JOIN (LEFT OUTER JOIN): only Order is loaded into the persistence context.
- LEFT JOIN FETCH (LEFT OUTER JOIN FETCH): Order and Customer are loaded into the persistence context.
- When Order fetches Customer with the LAZY strategy, and customer is null
- JOIN (INNER JOIN): only Order is loaded into the persistence context.
- JOIN FETCH (INNER JOIN FETCH): nothing is loaded.
- LEFT JOIN (LEFT OUTER JOIN): only Order is loaded into the persistence context.
- LEFT JOIN FETCH (LEFT OUTER JOIN FETCH): only Order is loaded into the persistence context.
- When Order fetches Customer with the EAGER strategy, and customer is not null
- JOIN (INNER JOIN): Order and Customer are loaded into the persistence context.
- JOIN FETCH (INNER JOIN FETCH): Order and Customer are loaded into the persistence context.
- LEFT JOIN (LEFT OUTER JOIN): Order and Customer are loaded into the persistence context.
- LEFT JOIN FETCH (LEFT OUTER JOIN FETCH): Order and Customer are loaded into the persistence context.
- When Order fetches Customer with the EAGER strategy, and customer is null
- JOIN (INNER JOIN): nothing is loaded.
- JOIN FETCH (INNER JOIN FETCH): nothing is loaded.
- LEFT JOIN (LEFT OUTER JOIN): only Order is loaded into the persistence context.
- LEFT JOIN FETCH (LEFT OUTER JOIN FETCH): only Order is loaded into the persistence context.
If you read the explanation for each JOIN below while looking at the example, it should be easier to understand.
- JOIN (INNER JOIN)
- Purpose: used to join related entities. It is mainly used when additional information is needed in the query’s WHERE clause or SELECT clause.
- Loading strategy: loads the related entity depending on that entity’s loading strategy, Lazy or Eager.
- Result: the base entity that does not match the join condition is excluded from the result.
- JOIN FETCH (INNER JOIN FETCH)
- Purpose: used to immediately load related entities.
- Loading strategy: forcibly loads the related entity immediately.
- Result: the base entity that does not match the join condition is excluded from the result.
- LEFT JOIN (LEFT OUTER JOIN)
- Purpose: used to join the base entity and related entity. Even if the related entity does not exist, the base entity is included in the result.
- Loading strategy: loads the related entity depending on that entity’s loading strategy, Lazy or Eager.
- Result: the base entity is always included in the result. If the related entity does not exist, it is treated as null.
- LEFT JOIN FETCH (LEFT OUTER JOIN FETCH)
- Purpose: used to immediately load the base entity and related entity together.
- Loading strategy: forcibly loads the related entity immediately.
- Result: the base entity is always included in the result. If the related entity does not exist, it is treated as null.