본문 바로가기
개발/JPA

[JPA] @OneToMany - 자식 테이블(관계 Entity)의 데이터를 상황에 따라 가져오기

by zuzuu 2021. 11. 26.
반응형

JPA를 사용하다 보면 LAZY 패치타입으로 relation이 달려 있는 엔티티를 조회할 때 n+1 문제가 발생하는 경우가 많다.

이럴 때는 @EntityGrapth만 달아주면 join하여 한번에 select할 수 있다. 

 

아래는 예시이다.

 

Product 테이블과 Sample 테이블은 1:N 관계이다.

따라서 sampleList에 @OneToMany 어노테이션을 설정해주었다. 

(반대로 Sample 엔티티에 Product를 @ManyToOne 설정해주어도 된다)

@Entity
@ToString
@Table(name = "PRODUCT")
public class Product{
	
    @Id
    @Column(name = "PRODUCT_ID", columnDefinition ="VARCHAR(36)")
    private String productId;
    
    //생략
    
    @OneToMany
    @JoinColumns({
    @JoinColumn(name = "SAMPLE_ID", referencedColumnName = "SAMPLE_ID", columnDefinition ="VARCHAR(36)", nullable = false, insertable = false, updatable = false),
    })
    @OnDelete(action= OnDeleteAction.CASCADE)
    private List<Sample> sampleList;
}

@OneToMany 속성에는 아래와 같은 것들이 있다.

  • targetEntity
  • cascade
  • fetch
  • mappedBy
  • orphanRemoval

여기서 fetch는 관계 Entity의 데이터 읽기 전략을 결정하며 EAGER, LAZY가 있으며, 따로 설정하지 않으면 기본은 LAZY이다.

EAGER로 설정할 경우 관계된 Entity의 데이터를 미리 읽어오고, LAZY로 설정할 경우 실제로 요청하는 순간에 가져온다.

따라서 엔티티에 EAGER 혹은 LAZY 둘 중 하나로 선택하여 세팅해야 하는데 본인은 상황에 따라 다르게 조회하고 싶었다.

(필요하지 않은데 데이터를 읽어오는 것은 효율이 떨어지기 때문에..)

 

 

해결방법

먼저 @OneToMany(fetch = FetchType.LAZY) 로 설정 하여 요청하는 순간에 가져오도록 하였다.

Product Repository에서 findAllById 를 하게 되면 Sample을 제외하고 Product에서만 조회한다.

하지만 이렇게 설정하면 또 문제가 발생한다. 조회된 Product 데이터에서 Sample에 접근하면 달려있는 Sample 개수 만큼 select 쿼리를 날린다. (n+1문제 발생)

 

Repository를 작성할 때 아래와 같이 @EntityGraph 어노테이션을 설정하면 join 쿼리가 실행된다.

@EntityGraph(attributePaths = {"sampleList"})
List<Product> findAllById(String product_id);

FetchType.LAZY로 설정하고, repository에서 이렇게 필요한 경우에만 @EntityGraph 어노테이션을 설정하여 join 쿼리를 실행하면 상황에 맞게 자식 엔티티를 조회하거나 조회하지 않을 수 있다.

 

 

 

 

728x90
반응형

댓글