참조가 있는 엔티티를 조회할때는 그 참조를 한번에 같이 즉시 조회할지 아니면 사용할때 조회할지에 대한 정의를 내려줘야한다.
즉시 로딩은 엔티티 객체 조회시에 한번에 다 가져오는 것이고,
지연 로딩은 참조의 메서드를 호출 했을 때, 초기화했을 때 그때 불러오는 것이다.
@ManyToOne과 @OneToMany의 fetch 전략은 기본이 즉시로딩이다. 이것을 지연로딩으로 바꾸려면 아래 코드와 같다.
@Entity
public class Member extends BaseEntity {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToOne(fetch = FetchType.LAZY) // EAGER은 즉시 가져오는 것
@JoinColumn
private Team team;
}
즉시로딩은 LAZY 대신에 EAGER을 사용하면 된다.
근데 즉시로딩은 가능하면 사용하면 안된다. 지연 로딩 위주로 사용해야 하는데, 즉시 로딩을 사용하게 되면 정말 예상하지 못하는 어마어마한 SQL 쿼리가 나갈 수 있다.
예를 들어 참조의 참조가 연쇄적으로 되어있는 엔티티가 있다고 가정하면, 심지어 1만개의 엔티티가 존재하면 그 모든걸 다 조회하는 쿼리가 날라가는 것이다. 이것은 성능상에서 큰 문제가 된다.
또한 JPQL에서 N+1 문제가 발생한다. 일반적으로 사용하는 em.find()는 JPA알아서 최적화를 다해줘서 1번만 쿼리가 나가는데 JPQL은 SQL문으로 변환되어서 쏘는 쿼리이다. 문제는 쌩 SQL을 날리는 거라 최적화가 안되기 때문에 어떤 엔티티를 조회하고 나면 뒤늦게 최적화를 하느라 나머지 참조를 불러오면서 쿼리가 또 나간다..
무조건 지연로딩으로 다 셋팅하고 즉시 로딩이 필요한 부분의 경우에는 JPQL의 fetch를 쓴다.
명심!
실무에스는 무조건 지연 로딩!
즉시 로딩이 필요하면 JPQL fetch 조인, 엔티티 그래프 기능을 사용.
'JPA' 카테고리의 다른 글
[JPA] orphanRemoval (0) | 2020.10.22 |
---|---|
[JPA] CASCADE (0) | 2020.10.22 |
[JPA] 프록시 (0) | 2020.10.22 |
[JPA] @MappedSuperclass (0) | 2020.10.20 |
[JPA] 상속관계 매핑 (0) | 2020.10.20 |