728x90
개요
스프링 JPA를 활용한 프로젝트 리팩토링 과정에서 JPA N+1 문제가 발생하여 정리해볼려고 한다.
Fetch 전략
특정 엔티티를 조회할 때, 연관된 다른 엔티티를 [언제] 불러오는지에 대한 옵션이다. 위와 같이 연관관계 매핑 어노테이션의 옵션을 통해 전략을 명시한다. 옵션에는 두 가지의 전략이 있다.
1. 즉시로딩
- 즉시로딩이란 연관된 모든 엔티티를 함께 즉시 로드하는 방식이다.
- 즉, 부모 엔티티를 조회할 때 연관된 자식 엔티티들도 함께 한번에 가져온다.
- 현재 엔티티를 조회한 [직후], 연관된 엔티티까지 조회한다.
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@ManyToOne(fetch = FetchType.EAGER) // 즉시 로딩
private User user;
}
위 Post 엔티티는 User와 다대일(@ManyToOne) 관계를 맺고 있으며, 즉시 로딩(EAGER)으로 설정되었다. 이 경우 Post를 조회할 때 User 정보도 함께 조회된다. 즉, Post 엔티티를 가져오면 바로 User 엔티티도 DB에서 쿼리되어 로드된다.
장점으로는 쿼리가 한 번만 실행되므로 사용 시 추가적인 데이터베이스 접근이 필요 없다. 이 방법으로 인해 N+1 문제를 해결할 수 있지만, 불필요하게 많은 데이터를 한 번에 로드할 수 있어 성능에 영향을 줄 수 있다.
2. 지연로딩
- 지연로딩이란 연관된 엔티티를 즉시 로드하지 않고 실제로 해당 엔티티에 접근할 때 데이터를 로드하는 방식이다.
- 즉 부모 엔티티만 먼저 조회하고 자식 엔티티는 실제로 필요할 때 쿼리가 발생하는 식이다.
- 현재 엔티티를 조회하고, [추후 필요할 때] 연관된 엔티티를 조회하는 쿼리를 날린다.
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@ManyToOne(fetch = FetchType.LAZY) // 지연 로딩
private User user;
}
위 Post 엔티티는 User와 지연 로딩(LAZY) 관계를 맺고 있다. 이 경우 Post 엔티티를 조회할 때는 User 엔티티를 바로 로드하지 않고, getUser() 메서드를 호출해서 User 정보를 실제로 사용할 때 DB에서 쿼리가 실행되어 데이터를 로드한다. 장점으로는 연관된 엔티티가 많아도 불필요한 데이터는 로드하지 않아 성능을 향상시킬 수 있다. 하지만 엔티티에 접근할 때마다 추가적인 데이터베이스 쿼리가 발생할 수 있다. 이를 잘못 사용할 경우 N+1 문제를 일으킬 수 있다.
기본 로딩 전략 (디폴트)
- @OneToMany, @ManyToMany: 기본적으로 지연 로딩(LAZY)으로 설정
- @ManyToOne, @OneToOne: 기본적으로 즉시 로딩(EAGER)으로 설정
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@ManyToOne // 기본 즉시 로딩 (EAGER)
private User user;
@OneToMany(mappedBy = "post") // 기본 지연 로딩 (LAZY)
private List<Comment> comments;
}
728x90
'Spring > Spring Boot' 카테고리의 다른 글
스프링 배치(Spring Batch) 사용하기 - 1편 (0) | 2024.09.10 |
---|---|
Spring : N+1 문제 해결 2편 - 문제 원인 분석과 해결 방법 (0) | 2024.09.09 |
Spring : @Builder 사용 하여 객체의 정보를 수정할 때 값이..?? (0) | 2024.08.30 |
Spring : @ModelAttribute & @RequestParam 차이 (0) | 2024.08.30 |
Spring : @Transactional 이란? (사용원리) (0) | 2024.08.29 |