반응형

오늘의 공부는 백기선님의 @ManyToOne 단방향 관계 쿼리 문제입니다.

원본 영상은 아래 링크를 참조해주세요~

 

 

Q . 왜 테스트 코드에서는 select 쿼리가 한 개만 발생하고 Controller 코드에서는 3개가 발생하는가?

테스트 코드의 트랜잭션의 범위는 testSelect 함수이다.

@DataJpaTest 어노테이션이 @Transactional 어노테이션을 가지고 있는데 이는 public 메서드들에 트랜잭션 단위를 부여하는 것과 동일하다. 즉 testSelect 함수 전체가 하나의 트랜잭션이다.

트랜잭션 하나에 Persistence Context 를 가지고 있으므로 save 를 할 때마다 1차 cache 에 저장된다.

그러므로 1차 cache 에서 바로 꺼낼 수 있기 때문에 다시 select 할 필요가 없다.

 

그런데 Controller 코드에서는 findAll 하나만 트랜잭션 범위이다.

기본 전략이 EAGER 이므로 Team 정보도 같이 가져올 수 밖에 없다.

Q . Member 정보만 쿼리 한 번으로 가져오려면 어떻게 해야 하는가?

LAZY 라는 Fetch 옵션을 사용하는 방법을 생각해 볼 수 있다.

Fetch 전략은 처음 Member 라는 정보를 조회해올 때 Team 을 참조하는 코드가 있지 않는 이상 Team 에 대한 데이터를 조회해오지 않는다. Team 에 대한 정보를 조회하는 순간이 오면 그 때 Team 에 대한 select 쿼리가 발생한다.

 

그러나, findAll 메서드는 객체를 JSON 형태로 변환해서 전달해 주는데 프록시인 객체를 JSON 으로 변환하려고 하니까 오류가 발생한다. LAZY 옵션을 사용하면 Team 에 대한 레퍼런스가 ByteBuddyInterceptor 라는 프록시 객체로 변경되기 때문이다. DTO 를 사용해서 modelmapper 로 다시 맵핑하면 된다.

 

댓글 중에 interface 를 사용하는 방법이 있다고 한다. projection!

Q . Member 와 Team 정보를 쿼리 한 번으로 가져오려면 어떻게 해야 하는가?

JPQL 에서 fetch join 을 사용하면 간단하게 해결이 될 것 같은데... JPQL 을 사용하지 않은 것을 전제로 하는 것 같다.

 

(공부해보니...)

fetch join 은 다음과 같은 단점도 존재한다. 같은 테이블을 조회하는 경우지만 어떤 테이블을 같이 조회하느냐에 따라 중복되서 쿼리를 작성하기 때문에 비추천한다고 한다.

 

@NamedEntityGraph 를 사용해서 Join 쿼리를 유도한다.

엔티티 그래프 기능은 엔티티 조회 시점에 연관된 엔티티들을 함께 조회하는 기능이다.

@NamedEntityGraph(name="엔티티 그래프 이름", attributeNodes={@NamedAttributeNode("함께 조회할 속성")})

반응형

'JAVA > JPA' 카테고리의 다른 글

[JPA][백기선] @OneToMany 양방향 관계 쿼리 문제  (0) 2022.04.09

+ Recent posts