JPA 게시글은 대부분 인프런의 김영한님의 강의인 '자바 ORM 표준 JPA 프로그래밍' 기반으로 내용을 정리했습니다.
경로 표현식
- .(점)을 찍어 객체 그래프를 탐색하는 것
select m.username // 상태 필드
from Member m
join m.team t // 단일 값 연관 필드
join m.orders o // 컬렉션 값 연관 필드
where t.name = "팀A"
- 위 세 가지 각자 내부적으로 동작하는 방식이 달라지므로 구분을 잘해서 이해해야 한다.
- 상태 필드(state field) : 단순히 값을 저장하기 위한 필드
- 연관 필드(association field) : 연관관계를 위한 필드
- 단일 값 연관 필드 : @ManyToOne, @OneToOne, 대상이 엔티티
- 컬렉션 값 연관 필드 : @OneToMany, @ManyToMany, 대상이 컬렉션
경로 표현식 특징
- 상태 필드(state field) : 경로 탐색의 끝, 탐색 X
select m.username From Member m
상태 필드의 경우 username 필드에 접근한 후 더 이상 접근할 필드나 속성이 존재하지 않는다. 그래서 더이상 탐색이 불가능하다.
- 단일 값 연관 경로 : 묵시적 내부 조인(inner join) 발생, 탐색 O
select m.team From Member m
단일 값 연관 경로의 경우엔 Member 안에 team에 접근 후 team안에 있는 다양한 필드에 더 접근할 수 있어 탐색이 가능하다.
m.team.name
위 표현식의 경우 name이 상태 필드인 경우엔 이 역시 경로 탐색의 끝이므로 더 이상의 탐색이 불가능하다.
묵시적 내부 조인의 경우엔 위 예제를 실행해보면 나오는 로그를 보면 알 수 있다.
Hibernate:
/* select
m.team
from
Member m */ select
team1_.id as id1_3_,
team1_.name as name2_3_
from
Member member0_
inner join //** join이 일어난다.
Team team1_
on member0_.TEAM_ID=team1_.id
이런 현상이 일어나는 이유는 객체에서야 점 표기법으로 간단하게 가져오면 되지만 DB에서는 Member에 있는 Team의 컬럼과 값을 가져오려면 어쩔 수 없이 join이 일어나게 된다. 이런 현상을 묵시적 내부 조인이라 한다.
뭔가 간단해 보여서 좋아 보이지만 오히려 실무에서는 잘 쓰지 않는다고 한다. 왜냐하면 쿼리 튜닝 부분에서 어려움을 겪을 수 있기 때문이다. 그래서 웬만하면 묵시적 내부 조인이 일어나지 않게 쿼리를 작성하는 것이 좋다. 그리고 또 다른 이유는 예제처럼 작성할 경우 의도치 않는 JOIN문이 계속 발생하면 한 번에 찾기가 힘들어서 웬만하면 JPA라도 큰 애플리케이션에서는 SQL과 비슷하게 작성하는 것이 좋다.
- 컬렉션 값 연관 경로 : 묵시적 내부 조인 발생, 탐색 X
- FROM 절에서 명시적 조인을 통해 별칭을 얻으면 별칭을 통해 탐색이 가능하다.
String query = "select t.members from Team t";
컬렉션의 경우 점 표기법으로 더 이상 가져올만한 게 없다. t.members 뒤에 점(.)을 찍으면 자동완성으로 나오는 게 size 밖에 없다. 즉, 탐색이 불가능하다. 만약 members에 있는 username을 가져오고 싶을 경우엔 명시적 조인을 사용하면 된다.
String query = "select m.username from Team t join t.members m";
- 뭔가 설명이 생각보다 복잡해졌지만 결론은 실무에서는 묵시적 내부 조인을 일으킬만한 쿼리를 작성하지 않는 것이 좋다.
단일 값 연관 경로 탐색
- JPQL : select o.member from Order o
- SQL
select m.*
from Orders o
inner join Member m on o.member_id = m.id
- 위 JPQL로 작성한 쿼리도 묵시적 내부 조인이 발생한다. 고로 사용하지 않는 게 좋다.
명시적 조인, 묵시적 조인
- 명시적 조인 : join 키워드 직접 사용
- select m from Member m join m.team t
- 묵시적 조인 : 경로 표현식에 의해 묵시적으로 SQL 조인 발생(내부 조인만 가능)
- select m.team from Member m
경로 탐색을 사용한 묵시적 조인 시 주의사항
- 항상 내부 조인
- 컬렉션은 경로 탐색의 끝, 명시적 조인을 통해 별칭을 얻어야 한다.
- 경로 탐색은 주로 SELECT, WHERE 절에서 사용하지만 묵시적 조인으로 인해 SQL의 FROM (JOIN) 절에 영향을 준다.
실무 조언
- 가급적 묵시적 조인 대신에 명시적 조인 사용
- 조인은 SQL 튜닝에 중요 포인트
- 묵시적 조인은 조인이 일어나는 상황을 한눈에 파악하기 어려움