[JPA] 즉시로딩(Eager)과 지연로딩(Lazy)
웹 프로젝트를 진행하던 중에 양방향 매핑 관계에서 발생한 N+1 문제를 겪었다.
N+1 문제의 이유와 해결 방법에 앞서 즉시로딩과 지연로딩에 대해 먼저 이해해야 한다고 생각한다.
즉시로딩과 지연로딩
즉시로딩과 지연로딩은 양방향 매핑이 되어 있는 두 Entity가 있고 한 Entity를 조회할 때 매핑된 Entity를 같이 조회할지, 실제로 매핑된 Entity의 조회가 필요한 시점에 조회할지를 정하는 방법이다.
비즈니스 로직에서 단순히 특정 Entity와 관련된 로직만 사용하는데 매핑된 Entity까지 조회하면 비효율적일 것이다. JPA는 이 문제를 지연로딩을 사용해서 프록시로 조회하는 방법으로 해결한다.
다음 예시를 통해 자세히 알아보자.
지연로딩(Lazy)
@Entity
@AllArgsConstructor
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private String password;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
private List<Post> postList;
}
@Entity
@AllArgsConstructor
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
private String writer;
@ManyToOne(fetch = FetchType.LAZY)
private User user;
}
- User, Post Entity가 있고 Post Entity를 조회하는 로직이 있다면, Post Entity가 로딩되는 시점에 Lazy 로딩 설정이 되어 있는 User Entity는 프륵시 객체로 가져온다.
- 후에 실제 객체를 사용하는 시점에 쿼리가 실행된다.
- getUser() 함수로 User를 조회하면 프록시 객체가 조회된다.
- getUser().getXXX() 함수로 User의 필드에 접근할 때, 쿼리가 실행된다.
- 대부분 로직에서 두 Entity를 같이 사용한다면 Lazy을 사용할 경우 select 쿼리가 2번씩 실행된다.
이는 속도가 매우 느린 디스크에 2번 엑세스해야 한다는 것이기 때문에 매우 비효율적이다.
이때는 즉시로딩(Eager)를 사용해 두 Entity를 함께 조회하는 것이 효율적이다.
즉시로딩(Eager)
@Entity
@AllArgsConstructor
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private String password;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
private List<Post> postList;
}
@Entity
@AllArgsConstructor
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
private String writer;
@ManyToOne(fetch = FetchType.EAGER)
private User user;
}
- 즉시로딩은 지연로딩과 달리 Entity 조회 할 때 프록시 객체가 아닌 조인을 사용해서 매핑된 Entity를 함께 조회한다.
- 가급적이면 즉시로딩을 사용하지 않는 것이 좋다.
- 즉시로딩을 사용하면 JPQL에서 N+1 문제가 발생한다. (지연로딩을 사용한다고 N+1 문제가 발생하지 않는 것은 아니다.. 다른 방법으로 해결해야 됨)
N+1 문제에 대해서는 다음에 포스팅할 것이다.
- 즉시로딩을 사용하면 JPQL에서 N+1 문제가 발생한다. (지연로딩을 사용한다고 N+1 문제가 발생하지 않는 것은 아니다.. 다른 방법으로 해결해야 됨)
Author And Source
이 문제에 관하여([JPA] 즉시로딩(Eager)과 지연로딩(Lazy)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@chjh121/JPA-즉시로딩Eager과-지연로딩Lazy저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)