inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

자바 ORM 표준 JPA 프로그래밍 - 기본편

조인

Eager로딩, 프로젝션, Fetch조인 복합적인 궁금증

해결된 질문

324

창신동 장첸

작성한 질문수 115

1

다른 분이 질문글에 잘 정리된 표를 올려주셔서 이것을 이용해 비교를 해보고 있습니다.

위 경우의 수에 번호를 붙여 왼쪽부터 차례로 ①~④ 번호를 매겼습니다.

질문1) 

강의 5분15초에 상황을 볼 때

위 그림③의 다른 점 한가지가 즉시로딩 입니다. 따라서 그림과 다르게 "Team 각각 N쿼리"가 윗 칸인 "User호출시점"에서 실행됩니다. 강의에서 잘 확인할 수 있었습니다.

그런데, JPQL에 setFirstResult(1).setMaxResult(10) 를 적용하면 1쿼리는 발생하지만 N쿼리가 질의되지 않은 것을 발견했습니다.

페이징을 적용하면 로딩방식이 Eager로 설정해도 무조건 Lazy로 진행이 되는 것인지요?

질문2)  

강의 5분15초에 상황에서 Eager설정을 유지하면서

SELECT m, t FROM Member m INNER JOIN m.team t

으로 프로젝션에 t를 추가했습니다. p.380 예제 10.35처럼(위 ④번) fetch조인의 SQL번역된 형식을 [일반JOIN + Eager]으로 모방할 수 있지않을까 궁금하여 실험해봤습니다.

결과는 SELECT문 질의가 발생하지 않았습니다.

왜 이런 결과가 나온것인지 궁금합니다.

java JPA

답변 1

0

김영한

안녕하세요. ddoddo님

테스트 해보신 것 둘다

아마 테스트 데이터가 부족하거나 아직 영속성 컨텍스트에 데이터가 남아있어서 캐시가 호출되어서 그런 문제가 발생할 거에요.

충분한 테스트 데이터를 추가하시고, 그 다음에 em.flush(), em.clear()를 호출해서 영속성 컨텍스트에 남아있는 엔티티를 제거한 다음에 다시 조회해보시면 원하는 결과를 보실 수 있을거에요.

감사합니다.

0

창신동 장첸

선생님, 죄송합니다.

몇 가지 실수를 발견했습니다. 그 때는 한 참 찾아도 못찾더니 지금와서 눈에 들어왔습니다ㅠㅠ

[질문1]

원인 : setFirstResult(1) 와 한 개의 입력데이터

행 1줄을 넣었기 때문에 setFirstResult( 1 ) 코드를 제거해야 정상인 결과를 얻을 수 있었습니다. setFirstResult( 1 )을 넣고 진행했던 강의실습을 그대로 따라갔다가 getResultList( )로 얻은 빈 리스트를 얻게 되었고 리스트에 요소가 없기 때문에 이후 Eager로딩으로 추가 N쿼리가 발생하지않았던 것입니다.... 흑흑

[질문2]

SELECT mt FROM Member m INNER JOIN m.team t 으로 질의를 할 때

em.createQuery(query, Member.class); 만 적었는데요. 이것이 실수였습니다.

프로젝션을 m, t로 잡았기 때문에 두 번째 파라미터는 제거를 해줘야 했습니다.(컴파일에러가 없어서 못 찾았은 거라 핑계를 대고 싶습니다)

잘못된 오류를 고치고 정상적으로 실행된 결과를 fetch조인과 비교해 보니 완전히 같은 것을 알 수 있었습니다.

즉, 

select m from Member m join fetch m.team t (fetch 조인) 

select m, t from Member m  join m.team t   (내부 조인 + 프로젝션명시) 

위 두 JPQL은 동일한 SQL쿼리로 변환되는 것을 확인할 수 있었습니다.

https://www.inflearn.com/questions/282782 예전에 질문글에 선생님께서 답변을 달아 주신적이 있었는데요. 저는 위 두 JPQL이 동일한 한 방 쿼리 결과를 만들어내 N+1문제를 해결해준다고 정리를 했습니다. 

상세한 정리는 아래 링크에 있습니다.

 링크  (다른 수강생분이 잘 정리된 표로 아이디어를 주셔서 응용하여 더 자세한 경우의 수를 정리해 봤습니다.)  

혹시나 잘못된 결론을 내린거라면 어떤 부분이 틀렸는지 조언부탁드립니다.

감사합니다.

0

김영한

select m, t from Member m  join m.team t는 사실 좀 특수한 경우입니다.

이렇게 사용하는 일은 거의 없습니다.

이게 성능 최적화가 된 것 처럼 보이는 이유는 다음과 같습니다.

JPA에서 엔티티를 조회하게 되면 엔티티는 모두 영속성 컨텍스트에 올라갑니다.

따라서 쿼리의 결과인 member도 모두 영속성 컨텍스트에 올라가고 team도 영속성 컨텍스트에 올라갑니다.

member.getTeam()을 호출하게 되면 지연로딩이 발생하는데, 방금 쿼리에서 team도 영속성 컨텍스트에 올라갔기 때문에 이미 로딩된 엔티티를 사용하게 됩니다.

fetch join은 명확하게 한번에 조회한다는 의미이기 때문에 성능 최적화가 필요하면 명확하게 fetch join을 사용해주세요. 

감사합니다.

벌크연산에서 member.getAge 호출 시 영속성 컨텍스트에서 데이터를 가져오는건가요?

0

55

2

inheritance startegy 선택시 고려사항

0

36

1

Entity 동등성 비교

0

38

1

실무 조언 관련 질문입니다.

0

64

1

H2데이터베이스 파일 생성

0

76

2

서브쿼리 강의에서 ALL 예시 관련 질문드립니다.

0

66

2

수정또는 삭제시 영속성 엔티티에 값이 무조건 있어야 하나요?

0

62

1

JPQL 메소드와 락

0

62

1

Delivery @OneToOne

0

70

1

17강 4~5분대 테이블 값 조회가 안됩니다.

0

104

2

UnsupportedOperationException 발생

0

97

3

H2 Database 연결이 안됩니다.

0

101

2

연관관계 매핑 질문드립니다.

0

93

2

h2데이터베이스 실행오류

0

114

2

persistence.xml

0

119

2

양방향 연관관계에서 연관관계의 주인(mappedBy)을 왜 꼭 정해야 하나요?

0

87

1

영속성 컨텍스트

0

74

1

JPA 프록시

0

105

1

Native Query와 MyBatis

0

81

1

영속성 컨텍스트는 어떤 메모리에 저장되는건가요?

0

97

1

임베디드 타입 예시 코드 관련 질문

0

125

3

명시적 조인에서 별칭을 주면 왜 객체에 접근할 수 있나요

0

100

3

인텔리제이 패키지 커서 단축키 질문

0

112

2

혹시 현재는 ID 데이터 타입이 String이면 안되나요?

0

151

1