Post

[JPA #5] 페치 조인과 JPQL의 다양한 기능

[JPA #5] 페치 조인과 JPQL의 다양한 기능

주요 키워드

  • 페치 조인(fetch join)
  • 다형성 쿼리
  • Named 쿼리
  • 벌크 연산

페치 조인 (Fetch Join)

  • join fetch 문법을 사용
  • JPQL의 distinct는 SQL의 DISTINCT를 추가할 뿐 아니라, 애플리케이션 레벨에서 엔티티 중복도 제거

일반 조인 vs 페치 조인

  • 일반 조인: 연관 엔티티를 즉시 조회하지 않음 → 이후 지연 로딩 발생
  • 페치 조인: 연관 엔티티까지 한 번에 함께 조회

페치 조인의 특징과 한계

  • 페치 조인 대상에는 별칭 사용 불가
    (Hibernate는 가능하나 사용 자제)
  • 두 개 이상의 컬렉션은 페치 조인 불가
  • 컬렉션 페치 조인 시 페이징 사용 불가
    • Hibernate는 경고 로그를 출력하고 메모리에서 페이징 처리 → 매우 위험

해결 방법

  1. 조인 순서 조정
    • xToMany → xToOne 순서로 변경
  2. 페치 조인을 제거하고 페이징 후 지연 로딩
    • N+1 문제가 발생할 수 있음
  3. @BatchSize 사용
    • 내부적으로 IN 쿼리 사용
    • persistence.xml에서 전역 설정 가능 (권장)
  4. 쿼리 전용 DTO로 조회

📌 통계성 쿼리처럼 엔티티의 구조와 전혀 다른 결과가 필요한 경우,
페치 조인보다 일반 조인 + DTO 매핑이 적합


다형성 쿼리

type

  • 특정 자식 타입만 조회할 때 사용
1
select i from Item i where type(i) IN (Book, Movie)

treat

  • 타입 캐스팅처럼 부모 → 자식으로 취급
1
select i from Item i where treat(i as Book).author = 'Kim'

엔티티 직접 사용

  • JPQL에서 엔티티를 직접 사용하면 SQL로 변환 시 해당 엔티티의 PK가 사용됨
1
select m from Member m where m.team = :team  -- team_id 비교

Named 쿼리 (@NamedQuery)

  • 미리 정의한 정적 쿼리에 이름을 부여해 사용하는 방식
  • @NamedQuery, orm.xml에 정의 가능
  • 애플리케이션 로딩 시점에 초기화 및 쿼리 검증 수행
  • 네이밍 관례: "엔티티명.쿼리명"
1
2
3
4
@NamedQuery(
  name = "Member.findByUsername",
  query = "select m from Member m where m.username = :username"
)
  • Spring Data JPA의 @Query도 내부적으로 NamedQuery로 등록됨

벌크 연산

  • JPA의 변경 감지로는 많은 엔티티 변경 시 비효율적
  • 직접 SQL을 실행 → executeUpdate() 사용
1
em.createQuery("update Member m set m.age = 20").executeUpdate();
  • 지원: update, delete (insert ... select는 Hibernate만 가능)
  • 영속성 컨텍스트를 무시하고 DB에 직접 반영
    • 이후 em.clear() 등으로 컨텍스트 초기화 필요
1
2
em.flush();
em.clear();  // 벌크 연산 후 영속성 컨텍스트 초기화 권장
This post is licensed under CC BY 4.0 by the author.