[JPA #5] 페치 조인과 JPQL의 다양한 기능
[JPA #5] 페치 조인과 JPQL의 다양한 기능
주요 키워드
- 페치 조인(fetch join)
- 다형성 쿼리
- Named 쿼리
- 벌크 연산
페치 조인 (Fetch Join)
join fetch
문법을 사용- JPQL의
distinct
는 SQL의DISTINCT
를 추가할 뿐 아니라, 애플리케이션 레벨에서 엔티티 중복도 제거함
일반 조인 vs 페치 조인
- 일반 조인: 연관 엔티티를 즉시 조회하지 않음 → 이후 지연 로딩 발생
- 페치 조인: 연관 엔티티까지 한 번에 함께 조회
페치 조인의 특징과 한계
- 페치 조인 대상에는 별칭 사용 불가
(Hibernate는 가능하나 사용 자제) - 두 개 이상의 컬렉션은 페치 조인 불가
- 컬렉션 페치 조인 시 페이징 사용 불가
- Hibernate는 경고 로그를 출력하고 메모리에서 페이징 처리 → 매우 위험
해결 방법
- 조인 순서 조정
- xToMany → xToOne 순서로 변경
- 페치 조인을 제거하고 페이징 후 지연 로딩
- N+1 문제가 발생할 수 있음
@BatchSize
사용- 내부적으로 IN 쿼리 사용
persistence.xml
에서 전역 설정 가능 (권장)
- 쿼리 전용 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.