인프런 커뮤니티 질문&답변

저스트님의 프로필 이미지

작성한 질문수

실전! 스프링 데이터 JPA

@EntityGraph

단순 조인과 페치 조인에 대한 추가 질문입니다.

작성

·

61

0

안녕하세요.

강의 항상 잘 보고 있습니다.

 

아래 두 질문 보고 이해가 안 되는 부분이 있어 질문 드립니다.

아래처럼 페치조인 사용하지 않고 member와 team을 select해서 가져올 경우에는 lazy 쿼리가 발생할 수 있다고 이해했습니다.

@Query("select m, t from Member m join m.team t")
List<Member> findInnerJoin();

 

team을 select하면 영속성 컨텍스트에도 team의 모든 pk가 저장되면서 lazy 쿼리가 발생하지 못하는 것은 아닌가요?

 

첫번째 링크 질문의 "이번 예제가 좀 특수한 경우고, 일반적으로 team이 영속성 컨텍스트에 미리 존재하는 경우는 드물기 때문에" 라는 답변에서 어떻게 team이 미리 존재하지 않는 경우가 생길 수 있는지 궁금합니다...

 

답변 2

0

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 저스트님

select m, t from Member m join m.team t

여기서 select 절에 member, team을 조회했는데요. 이렇게 되면 영속성 컨텍스트에서 member, team 둘다 관리됩니다.

이 상태에서 member.getTeam()을 호출하게 되면 영속성 컨텍스트에서 관리되는 team이 조회됩니다. 따라서 지연 로딩에서 초기화가 발생하지 않습니다.

 

select m from Member m join m.team t

여기서 select 절에 member만 조회했는데요. 이렇게 되면 영속성 컨텍스트에서 member만 관리됩니다.

이 상태에서 member.getTeam()을 호출하게 되면 영속성 컨텍스트에는 team이 없기 때문에 지연 로딩의 초기화가 발생합니다.

 

감사합니다.

저스트님의 프로필 이미지
저스트
질문자

답변 감사합니다.

 

결국 제가 궁금한 것은 아래 쿼리(단순 조인)와

select m, t from Member m join m.team t

아래 쿼리(페치 조인)와의 차이점인데 명확하게 모르겠습니다...

select m from Member m join fetch m.team t

 

단순 조인 시 m, t을 함께 select하면

team이 영속성 컨텍스트에 있어 지연 로딩을 초기화하지 않으니

페치 조인과 똑같지 않나 하는 생각이 듭니다.

 

그런데 본문 첫번째 링크 질문의 "이번 예제가 좀 특수한 경우고, 일반적으로 team이 영속성 컨텍스트에 미리 존재하는 경우는 드물기 때문에" 라는 말에서

 

m, t을 select 시 team을 가져와 영속성 컨텍스트에 있는데

어떻게 미리 존재하는 경우가 드물다고 말씀하신 것인지 이해가 안 됩니다...

김영한님의 프로필 이미지
김영한
지식공유자

페치 조인의 목적은 하나의 엔티티를 조회할 때 연관된 엔티티를 함께 한 번에 조회하는 것이 목표입니다. 따라서 SQL 실행 한번으로 Member를 조회할 때 연관관계에 있는 Team이 함께 조회됩니다.

이때 Member -> Team의 연관관계는 프록시가 아니라 실제 객체로 존재합니다.

 

첫번재 방법인 단순 조인은 Member와 Team을 둘다 조회하기 때문에 둘다 영속성 컨텍스트에 존재는 합니다. 다만 Member에 Team이 연결된 상태가 아닙니다. 둘은 완전히 서로 따로 조회된 상태라고 보시면 됩니다.

이때 Member -> Team의 관계는 프록시 상태로 존재합니다 (물론 lazy로 설정해야함)

따라서 Member -> Team을 조회할 때 Team을 다시 찾아야 합니다. 이때 지연 로딩에 의해서 영속성 컨텍스트를 찾아서 연결이 되는 원리입니다.

 

JPA에서는 연관된 엔티티를 함께 조회할 때 일반적으로 페치 조인을 사용한다고 이해하시면 됩니다.

감사합니다.

저스트님의 프로필 이미지
저스트
질문자

상세하게 알려주셨음에도 계속 질문드려 죄송합니다.

 

페치 조인은 지연 로딩과 상관 없이 바로 DB에서 조회하는 것이고,

 

단순 조인은 지연 로딩에 영향을 받아 영속성 컨텍스트에 있으면 영속성 컨텍스트에서 가져오고, 영속성 컨텍스트에 없을 경우 DB에서 조회한다.

(다만 단순 조인 select 시 이미 DB에서 team을 가져왔기 때문에 영속성 컨텍스트에서 가져온다.)

 

결국 페치 조인은 DB에서 가져온 후 영속성 컨텍스트에서 가져오는 과정이 없기 때문에 이점이 있다 정도로 이해하면 될까요?

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 저스트님

네 생각하신 부분이 맞습니다 🙂

여기서 확실히 차이를 이해하려면, 단순 조인시 select 절에 team을 적지 않으면 team은 영속성 컨텍트에 올라가지 않습니다.

select m from Member m join m.team t

이렇게 되는 경우 member 조회하기 때문에 영속성 컨텍스트에는 member만 올라갑니다.

감사합니다.

저스트님의 프로필 이미지
저스트
질문자

자세한 설명 감사합니다!

0

안녕하세요, 인프런 AI 인턴입니다.

저스트님의 질문에 대해 답변드립니다.

먼저 질문해주신 부분이 단순 조인과 페치 조인의 차이점에 관한 내용입니다. 일반적으로 단순 조인으로 조회할 경우, 지연 로딩(Lazy Loading)이 설정된 연관 엔티티는 실제로 사용되는 시점에 쿼리가 추가로 발생하게 됩니다.

단순 조인과 Lazy 로딩

@Query("select m, t from Member m join m.team t")
List<Member> findInnerJoin();

위의 쿼리는 MemberTeam을 조인하여 결과를 가져오는 단순 조인 쿼리입니다. 이때 Member와 연관된 Team의 정보는 함께 조회되지만, Member 엔티티에서 Team 속성이 실제로 접근될 때까지는 Lazy Loading이 적용되어 쿼리가 추가로 발생하지 않습니다. 하지만 이렇게 되면 영속성 컨텍스트에 의해 관리되지 않은 상태로 존재하게 됩니다.

이런 경우, Lazy Loading이 작동하면서 추가적으로 필요한 시점에 쿼리가 발생합니다.

페치 조인과 즉시 로딩

페치 조인을 사용하면 Lazy Loading 설정 여부와 관계없이 조인된 연관 엔티티를 한 번에 가져오게 됩니다.

@Query("select m from Member m join fetch m.team")
List<Member> findFetchJoin();

위의 쿼리는 페치 조인을 사용하여 Member와 연관된 Team 엔티티를 한 번에 가져오며, 이로 인해 추가적인 Lazy Loading 쿼리가 발생하지 않습니다. 페치 조인을 사용하면 이처럼 연관된 엔티티를 미리 가져와 영속성 컨텍스트에 저장하며, 지연 로딩(Lazy Loading) 쿼리가 발생하지 않게 됩니다.

영속성 컨텍스트의 중요성

강의에서는 “일반적으로 Team이 영속성 컨텍스트에 미리 존재하는 경우는 드물기 때문에”라고 설명되어 있습니다. 이는 대부분의 경우, 연관된 데이터가 한 번에 조회되는 경우가 많지 않으며, 필요 시마다 해당 데이터를 가져오는 방식으로 설계되기 때문입니다. 따라서 페치 조인을 사용하지 않으면 자연스럽게 Lazy Loading에 의해 추가 쿼리가 발생하게 됩니다.

유사한 질문 링크 참고

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.