[JPA] 경로 표현식
📌 Topic
- 💡 JPQL 경로 표현식
⚡ 01. JPQL 경로 표현식
01-1 경로 표현식
select m.username -- 상태 필드
from Member m
join m.team t -- 단일 값 연관 필드
join m.orders o -- 컬렉션 값 연관 필드
where t.name = '팀A'
경로 표현식이란 .(점)을 찍어 탐색하는 것을 의미한다. 우선 위 SQL을 보는 것만으로는 이해가 쉽게 되지 않으니 다음 경로 표현식 용어 정리를 살펴보자.
- 상태 필드
- 단일 값 연관 필드
- 컬렉션 값 연관 필드
01-2. 경로 표현식 용어 정리
// Entity : Member
// target : 단일 값 연관 필드
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private JpqlTeam team;
// Entity : Member
// target : 컬렉션 값 연관 필드
@OneToMany(mappedBy = "member")
private List<Order> order = new ArrayList<>();
- 상태 필드(state field)
- 단순히 값을 저장하기 위한 필드 (ex : m.username)
- 연관 필드(association field)
- 연관관계를 위한 필드
- 단일 값 연관 필드
- @ManyToOne @OneToOne
- 타겟 대상이 엔티티인 경우
- 컬렉션 값 연관 필드
- @OneToMany, ManyToMany
- 타겟 대상이 컬렉션인 경우
- 단일 값 연관 필드
- 연관관계를 위한 필드
01-3. 경로 표현식 특징
// m.username에 다음에 '.' 을 찍어서 탐색이 불가능 하다.
// 즉, 상태 필드는 경로 탐색의 끝이라 할 수 있다.
String query = "select m.username.컬럼or엔티티 From JpqlMember m";
List<String> resultList = em.createQuery(query, String.class)
.getResultList();
- 상태 필드(state field)
- 경로 탐색의 끝이다.
- 그래프 탐색은 불가능하다.
- m.username 다음에 ‘.’을 찍어서 접근이 불가능하기 때문이다.
// 단일 값 연관 필드
// @ManyToOne, @OneToOne 참조를 하면 탐색이 가능하고
// -> (중요) 묵시적 내부 조인이 발생한다
String query = "select m.team From JpqlMember m";
List<JpqlTeam> resultList = em.createQuery(query, JpqlTeam.class)
.getResultList();
for (JpqlTeam team : resultList) {
System.out.println("team = " + team);
}
// 해당 JPQL을 실행한 결과, 묵시적 내부 조인(INNER JOIN) 발생
// m.team을 통해 team만 가져오라고 했는데, Member와 Team을 조인해서 가져온다.
Hibernate:
/* select
m.team
From
JpqlMember m */ select
jpqlteam1_.TEAM_ID as team_id1_13_,
jpqlteam1_.name as name2_13_
from
JPQL_MEMBER jpqlmember0_
inner join
JPQL_TEAM jpqlteam1_
on jpqlmember0_.TEAM_ID=jpqlteam1_.TEAM_ID
- 단일 값 연관 경로
- 묵시적 내부 조인(INNER JOIN) 발생
- 그래프 탐색이 가능하다.
- m.team 다음에 ‘.’을 찍어서 다른 상태 필드나 참조 변수에 접근이 가능.
- 묵시적 내부 조인이 발생 하도록 설계를 하면 안된다.
- 묵시적 내부 조인은 쿼리 튜닝 역시 쉽지가 않다.
// 컬렉션 값 연관 경로
String query = "select t.memberList From JpqlTeam t";
Collection resultList = em.createQuery(query, Collection.class)
.getResultList();
- 컬렉션 값 연관 경로
- 묵시적 내부 조인 발생
- 그래프 탐색은 불가능하다.
- FROM 절에서 명시적 조인을 통해 별칭을 얻으면 별칭을 통해 탐색 가능.
💡 묵시적 조인은 사용하지 말고, 명시적 조인을 사용해야 한다.
01-4. 단일 값 연관 경로 탐색
// JPQL
// 묵시적 내부 조인 발생, 상당히 위험하다
select o.member from Order o
-- SQL
-- 위 JPQL 쿼리와 아래 SQL문이 동일하다 봐도 무방
select m.*
from Orders o
inner join Member m on o.member_id = m.id
01-5. 명시적 조인, 묵시적 조인
실무에서는 웬만하면 명시적 조인을 사용하여 데이터를 조회 해야 한다
- 명시적 조인
- join 키워드를 직접 사용한다.
- 묵시적 조인
- 경로 표현식에 의해 묵시적으로 SQL 조인 발생(내부 조인만 가능)
- select m.team from Member m
01-6. 경로 표현식 - 예제
// 성공 여부 - o
select o.memeber.team
from Order o
- 조회는 가능하다.
- 하지만 묵시적 내부 조인이 3번이나 발생한다.
- 내부적으로 어떤 쿼리가 날라가는지 파악이 힘듬.
// 성공 여부 - o
select t.memberList from Team
- 컬렉션에서 끝이 났기 때문에 가능하다.
- Member(1) : team(N) 관계로 봐주면 된다.
// 성공 여부 - x~
select t.memberList.username from Team t
- 컬렉션 값 연관 관계는 그래프 탐색이 불가능하다.
- 탐색을 하려면 명시적 조인을 사용하여 값을 가져와야 한다.
// 성공 여부 - o
select m.username from Team t join t.memberList m
- 명시적 조인을 사용하여 별칭인 ‘m’ 을 통해 값을 출력할 수 있다.
- 위에서 불가능 했던 부분이다.
01-7. 경로 탐색을 사용한 묵시적 조인 시 주의사항
- 항상 내부 조인을 수행한다.
- 항상 내부 조인을 하기 때문에 반드시 유의하여 사용을 해야 한다.
- 컬렉션은 경로 탐색의 끝, 명시적 조인을 통해 별칭을 얻어야 한다.
경로 탐색은 주로 SELECT, WHERE 절에서 사용하지만 묵시적 조인으로 인해
SQL의 FROM(JOIN) 절에 영향을 줄 수 있다
⚡ 02. 실무 조언
- 항상 묵시적 조인 대신에 명시적 조인을 사용해야 한다.
- 조인은 SQL 튜닝에 있어 상당히 중요한 포인트다.
- 묵시적 조인은 조인이 일어나는 상황을 한 눈에 파악하기가 어렵다.
- 즉, 명시적 조인을 사용하자.
댓글남기기