본문 바로가기
Spring JPA

[Spring] 즉시(Eager) 로딩 과 지연(Lazy) 로딩

by fiat_lux 2024. 8. 11.

Spring jpa 에서 연관관계 매핑을 할때 설정하는 문제이다 

JPA 에서 데이터를 조회 할때 eager loading(즉시 로딩), lazy loading(지연 로딩) 으로 하는 두가지 방식이 있다

이 두개의 차이점은 한개의 테이블을 조회할때 그 테이블에 연관된 테이블까지 불러오냐 안 불러오냐의 차이점이다

 

여기서 즉시 로딩(eager)은 연관된 데이터까지 한 번에 불러오고

지연 로딩(lazy)은 필요한 시점에 연관된 데이터를 불러온다

 

어떻게 설정을 하냐?

@Entity
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "post")
public class Post {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "post_id")
    private Long postId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    @Column(name = "title")
    private String title;

    @Column(name = "content")
    private String content;

}

 

일단, 해당하는 테이블의 연관관계 1:N, N:1, 1:1 등등을 설정해주고 fetch  타입을 지정해준다

 

Fetch Type 이란?

 

JPA가 하나의 Entity를 조회할 때 연관관계에 있는 객체들을 어떻게 가져올 것이냐를 나타내는 설정값이다

 

여기에서 JPA는 ORM 기술이다

사용자가 쿼리를 직접 작성하지 않고 JPQL을 이용하여 쿼리문을 생성하기 때문에 

객체와 필드를 보고 쿼리를 생성한다

 

 

즉시 로딩 

  • 데이터를 조회할 때 연관된 모든 객체의 데이터까지 한번에 불러오는 것
  •  @xxToxx(fetch = FetchType.EAGER)
@Entity
@Getter
@Setter
@Table(name = "category")
@NoArgsConstructor
public class Category {

    @Id
    @Column(name = "category_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "parent_category_id")
    private Category parentCategory;

    @Column(name = "category_name")
    private String name;

    public Category(Category parentCategory, String name) {
        this.parentCategory = parentCategory;
        this.name = name;
    }
}

 

이렇게 category라는 entity가 있고 부모 카테고리와 N:1의 관계를 가지고 있다고 보자 

category 한개를 조회할 때 어떤 쿼리가 만들어질까 ?

Hibernate: 
select c1_0.category_id,c1_0.category_name,pc1_0.category_id,pc1_0.category_name,pc1_0.parent_category_id 
	from category c1_0 
left join category pc1_0 on pc1_0.category_id=c1_0.parent_category_id 
where c1_0.category_id=?

위와 같이 즉시 로딩을 사용하게 되면 category를 조회할때 부모 카테고리 까지 불러오는 쿼리를 작성하여 한꺼번에 데이터를 불러온다

 

 

지연 로딩 

  • 필요한 시점에 연관된 객체의 데이터를 불러온다
  • @xxToxx(fetch = FetchType.LAZY)

위에 있는 Category entity에서 FetchType 을 Lazy로 바꾼다면 어떤 쿼리가 만들어질까?

Hibernate: 
select c1_0.category_id,c1_0.category_name,c1_0.parent_category_id 
	from category c1_0 
where c1_0.category_id=?

위와 같이 부모 카테고리의 데이터까지는 불러오지 않는다 

즉, 지연 로딩을 사용하면 연관된 데이터는 사용하는 시점에 쿼리가 나가도록 할 수 있다 


 

어떤 사람들은 "어차피 가져와야 하는 데이터면 EAGER가 좋지 않냐?"라고 말하기도 한다

그러나, EAGER 로딩을 무조건적으로 사용하는 것은 바람직하지 않다

 

EAGER 로딩은 연관된 모든 데이터를 한 번에 가져오므로, 불필요한 데이터가 함께 로딩되어 성능 문제를 야기할 수 있다

 

만약 특정한 경우, 예를 들어 카테고리와 부모 카테고리가 항상 함께 사용되는 상황이라면, EAGER로 설정하여 데이터를 함께 조회하는 것이 합리적일 수 있다

 

그러나 해당 엔티티를 조회할 때 연관된 데이터가 당장 필요하지 않거나, 특정 시점에만 필요한 경우라면 LAZY 로딩을 사용하는 것이 좋다 이 경우에는 필요한 시점에 별도의 쿼리를 작성하여 데이터를 가져오는 것이 성능 면에서 더 유리하다