-
[Spring JPA] JPA, JPQL 의 조인 시 주의할 점 (Outer, Inner, Fetch)Back End/Spring Data JPA 2022. 1. 29. 13:47
JPQL 은 EntityManager 의 관리를 받아 SQL 쿼리를 번역하여 날리는 번역기 정도라고 생각했다.
공용어에서 각 DB마다의 방언으로 바꾸어주는데, 이와 동시에 EntityManger의 관리를 받으므로, 하이버네이트 특유의 쿼리동작과 영속성관리를 받는다.
진행하는 개인프로젝트에서는 쿼리가 맘에안들면 QueryDSL로 작업을 했고, 쓸데없는 JOIN문이 최대한 발생하지 않게끔 엔티티를 설계했기 때문에 JPA Query Method를 사용해도 이러한 현상을 목격하지 못했었는데 김영한님의 강의를 보다가 내가 겪어보지 못한 신기한 현상에 대한 설명을 하시는 것을 보고 기록으로 남겨두고자 포스팅한다.
사실 JPQL의 조인이라기 보다는 JPA의 조인현상이라고 보는게 맞을 것 같다.
SQL 과 ORM의 간극을 줄이기 위한 현상인데, 모르고 있으면 뒤통수 맞을 확률이 높다.
아래는 TEAM 과 MEMBER 테이블이며, DB에 데이터가 아래와 같이 저장되어있다고 하자.
# DB 테이블 현황
이제 INNER JOIN 과 OUTER JOIN 을 실행해보자
# INNER JOIN
# OUTER JOIN
위의 그림을 머리에 넣어두고 JPQL에서 현상을 비교해보자.
# JPQL 예제
>>> 1 번
String query = "select t From Team t join t.memebers"; List<Team> result = em.createQuery(query, Team.class).getResultList(); // >> JPQL 로 생성된 SQL 쿼리 // >> SELECT t.id, t.name FROM Team t INNER JOIN Member m on t.id=m.id;
result.size() 는 몇일까? 필자는 여태 2로 알고 있었다.
근데 아니다.... 4이다...
JPQL로 생성된 SQL 쿼리의 결과는 아래와 같다.
SQL을 잘모르시면 Team 의 데이터가 3개니까 size는 3이겠지! 하시는 분들도 있었을 것 같다...
무튼 SQL 쿼리의 결과 값의 사이즈는 4이고, JPA는 이 테이블을 그대로 결과 값으로 가져온다.
정말 당황스럽지 않은가...? Team 객체안에 Member가 있으니, 모든 Team에 속한 Member를 조회하려면
Team 레코드 2개만 있어도 되는데, 객체지향적이 아닌 너무나도 SQL 지향적이다.
이게 어떻게 ORM이야!!!
이를 객체지향적으로 바꿀 수 있는 JPQL 키워드가 있긴하다.
바로 distinct 인데 sql 에 distinct 키워드를 추가해주는 것 뿐만아니라,
애플리케이션 단에서 객체 지향에 맞게 중복을 제거하는 기능도 같이 한다.
>>> 2번
String query = "select distinct t From Team t join t.memebers"; List<Team> result = em.createQuery(query, Team.class).getResultList(); // >> JPQL 로 생성된 SQL 쿼리 // >> SELECT distinct t.id, t.name FROM Team t INNER JOIN Member m on t.id=m.id; String query2 = "select distinct t From Team t join fetch t.memebers"; List<Team> result2 = em.createQuery(query, Team.class).getResultList(); // >> JPQL 로 생성된 SQL 쿼리 // >> SELECT distinct t.id, t.name, m.id, m.name FROM Team t INNER JOIN Member m on t.id=m.id;
해당 JPQL 의 결과 result.size() 와 result2.size() 는 모두 2이다.
하지만 해당 JPQL의 변환된 SQL 문의 레코드는 이렇다.
728x90'Back End > Spring Data JPA' 카테고리의 다른 글
[Spring JPA] @MappedSuperClass 사용시 주의할 점 (0) 2022.03.04 save() 메서드 호출 시, select 쿼리가 하나 더 나가요 ㅠㅠ... (1) 2022.02.17 [Spring JPA] How to retrieve Only SuperClass from a class hierarchy. (0) 2022.01.28 [Spring JPA] Interface-Based Projection doesn't work. (0) 2022.01.28 [Spring JPA] 복합키(PK)의 성능을 알아보자! (0) 2022.01.26