1. 내부 조인
join(조인 대상, 별칭으로 사용할 Q타입)
List<Member> result = queryFactory
.selectFrom(member)
.join(member.team, team)
.where(team.name.eq("teamA"))
.fetch();
▪️ 조인 대상은 연관관계가 있는 필드로 조인해야한다.
▪️ Q타입을 별칭으로 사용해야한다.
SQL에서는 별칭을 임의로 지정하는 것이 가능하지만, Querydsl에서는 Q타입클래스만 별칭으로 지정해줄 수 있다.
▪️ 별칭을 왜 Q타입으로 쓰는지, 별칭이 필수인지 궁금했지만 관련자료를 찾지 못했다.
별칭을 생략해도 코드는 잘 돌아가는 걸 확인했다.
별칭을 사용하는 것이 조인 대상을 명확히 하기 때문에 가독성 면에서 더 좋은 것 같다.
(where절에 쓰이는 team은 QTeam이다.)
▪️ on절에 따로 명시해주지 않아도, on team.team_id=member.team_id 엔티티를 매핑해주는 on절이 자동으로 생성된다.
2. 세타조인
List<Member> result = queryFactory
.select(member)
.from(member, team)
.where(member.username.eq(team.name))
.fetch();
▪️ 엔티티 간의 연관관계가 없을 때는 세타조인을 한다.
▪️ 내부조인과 달리, 세타조인은 from 뒤에 조인할 엔티티들을 나열한다.
▪️ 연관관계가 없기 때문에 엔티티 매핑 조건이 생성되지 않는다.
▪️ 세타조인은 이전에 외부조인이 안됐었지만, on절을 쓰면 외부조인을 할 수 있다. (하이버네이트 5.1 부터)
3. on 조건절( JPA2.1부터 지원 )
✅조인 대상 필터링
List<Tuple> result = queryFactory
.select(member,team)
.from(member)
.leftJoin(member.team, team)
.on(team.name.eq("teamA"))
.fetch();
▪️ left join, right join과 같은 외부 조인을 할 때는 on절로 조인 대상을 필터링 해야한다.
외부 조인을 쓰고 where절로 필터링 하려고 하면 원하는 결과를 얻지 못한다.
where절은 조회 결과를 필터링할 때 쓰는 조건절이기 때문에 on절과 구분해서 써야한다.
실행 쿼리
/* select
member1,
team
from
Member member1
left join
member1.team as team with team.name = ?1 */ select
m1_0.member_id,
m1_0.age,
m1_0.team_id,
m1_0.username,
t1_0.team_id,
t1_0.name
from
member m1_0
left join
team t1_0
on t1_0.team_id=m1_0.team_id
and t1_0.name=?
✅세타조인 + 외부 조인
하이버네이트 5.1부터 세타조인으로도 외부조인을 할 수 있다.
List<Tuple> result = queryFactory
.select(member, team)
.from(member)
.leftJoin(team).on(member.username.eq(team.name))
.fetch();
leftJoin에 연관관계를 명시하지 않고 on절을 써주면 된다.
실행 쿼리
/* select
member1,
team
from
Member member1
left join
Team team with member1.username = team.name */ select
m1_0.member_id,
m1_0.age,
m1_0.team_id,
m1_0.username,
t1_0.team_id,
t1_0.name
from
member m1_0
left join
team t1_0
on m1_0.username=t1_0.name
실행된 쿼리를 보면 연관관계 있는 엔티티를 외부조인 했을 때는 on t1_0.team_id=m1_0.team_id 조건이 붙지만 세타조인을 할 때에는 이 조건이 따로 붙지 않는다.
4. 페치조인(fetchJoin)
페치조인은 SQL에서 제공하는 기능은 아니다.
엔티티에 연관관계 필드를 정의할 때, 보통 지연로딩으로 설정을 하지만 때로 지연로딩 때문에 N+1 문제가 생기기도 한다.
이럴때 페치조인으로 N+1문제를 해결해서 성능 최적화를 할 수 있다.
//JPQL : select m from Member m join fetch m.team where m.username = "member1"
Member findMember = queryFactory
.selectFrom(member)
.join(member.team, team).fetchJoin()
.where(member.username.eq("member1"))
.fetchOne();
▪️ join을 쓰고 뒤에 fetchJoin()만 붙여주면 된다.
✅페치조인 적용 테스트
@PersistenceUnit
EntityManagerFactory emf;
@Test
public void fetchJoinUse(){
em.flush();
em.clear();
Member findMember = queryFactory
.selectFrom(member)
.join(member.team, team).fetchJoin()
.where(member.username.eq("member1"))
.fetchOne();
boolean loaded = emf.getPersistenceUnitUtil().isLoaded(findMember.getTeam());
assertThat(loaded).as("페치 조인 적용").isTrue();
}
▪️ @PersistenceUnit 어노테이션으로 EntityManagerFactory를 주입받는다.
EntityManagerFactory를 통해 PersistenceUnitUtil객체를 사용하기 위해서다.
▪️ 이전에 했던 테스트에 영향을 받을 수 있으니 영속성 컨텍스트를 초기화 해준다.
▪️ PersistenceUnitUtil객체는 엔티티의 상태와 관련된 유틸리티 메서드를 제공하는 인터페이스다.
isLoaded()메서드로 findMember 엔티티의 team 속성이 페치 조인으로 로드 됐는지 여부를 확인한다.
'인프런 김영한 강의 정리 > 실전! Querydsl' 카테고리의 다른 글
[Querydsl] 기본 문법(4) - Case문 (0) | 2024.08.09 |
---|---|
[Querydsl]기본 문법(3) - 서브 쿼리 (0) | 2024.08.09 |
[Querydsl] fetchResults(), fetchCount() 대체하기 (0) | 2024.08.07 |
[Querydsl] 기본 문법(1) - JPQL과 차이, 조회 (0) | 2024.08.06 |
프로젝트 환경설정 (SpringBoot 3.x 버전), Querydsl 설정 (0) | 2024.07.27 |