프로젝트를 하며 대부분의 경우에서는 FetchType = LAZY라고 할 정도로 보편적으로는 lazy를 쓴다는 것은 알고 있다.
물론 프로젝트를 하며 FetchType.LAZY를 사용할 때도 어떤 점이 장점으로 부각되는지는 알아보았으나, 정리를 따로 해두지를 않았기 때문에 이번 기회에 FetchType에 대해 좀더 자세히 알아보기로 했다.
그렇다면 우선 FetchType이 무엇인지부터 알아보자.
관심없다구요? 그럼 왜 읽ㅇ
FetchType
: JPA가 하나의 Entity를 조회할 때, 연관관계에 있는 객체들을 어떻게 가져올 것이냐에 대한 설정값
JPA가 무엇인지 모를 수도 있는 사람들을 위해(간단하게 요약한 것이기 때문에 궁금하면 따로 공부해보자)
✔JPA(Java Persistance API)
- Java 에서 ORM(Object-Relational Mapping) 기술 표준으로 사용하는 인터페이스 모음
- 자바 어플리케이션에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스
- 인터페이스이기에 Hibernate,OpenJPA 등이 JPA를 구현한다.
JPA 기본 패치 전략
@ManyToOne, @OneToOne : 즉시 로딩
- optional = false : 내부 조인
- optional = true : 외부 조인
@OneToMany, @ManyToMany : 지연 로딩
- optional = false : 외부 조인
- optional = true : 외부 조인
xToMany 나 xToOne에 명시적으로 FetchType.LAZY를 전부 명시해주면 문제없지만, default값이 있기 때문에 메모하겠다.
✔ Default FetchType
@OneToOne : EAGER
@XToMany : LAZY
부연설명을 넣자면, 하나만 로딩해도 될때는 EAGER를 통해 즉시 로딩 되도록,
많은 데이터가 로딩되어야 할때는 지연로딩 되도록 설정되어 있다.
즉시 로딩
👌FetchType.EAGER
- 연관된 엔티티를 즉시 조회한다. HIBERNATE는 가능하면 SQL조인을 사용해 한 번에 조회한다.
- 즉시 로딩을 사용하려면 FetchType을 EAGER로 설정하면 되지만, DEFAULT로 EAGER가 설정된 경우도 있지만 명시적으로 표시해줘도 무관하다
- JPA 구현체는 즉시 로딩을 최적화하기 위해 조인쿼리를 일반적으로 사용한다. HIBERNATE는 가능하면 SQL조인을 사용해 한 번에 조회한다.
위는 보편적으로 많이 알고 있는 EAGER의 특징일 것이다.
아래 쓸 내용들 때문에 보편적으로 EAGER가 아닌 LAZY를 사용하는 것이다.
✅일반적으로 EAGER를 쓰지 않는 이유
1. EAGER를 사용할 경우 예상치 못한 SQL이 나타날 확률이 높다.
-> 다른 객체를 가져올 때 join을 사용해 가져올지, select를 두 번 할지 모른다는 것이다.
2. join이 여러 번 겹치는 경우 성능상 문제가 발생할 수 있다
-> 당장 필요없는 데이터인데 join을 통해 가져올 시에, 성능상 문제가 발생할 수도 있다는 것이다.
(join의 시간복잡도는 지수함수로 증가하기 때문이다.) 때문에 불필요한 경우 대비를 하는 것이 좋다.
3. 즉시로딩은 JPQL에서 N+1문제의 원인이 된다.
-> JPQL은 JPA와 달리 최적화된 것이 아니기에 SQL로의 변환 작업만 해주면 되기 때문이다.
-> 위 1번에서 select를 여러 번 날리는 쿼리가 이 경우 많이 발생된다.
지연 로딩
👌FetchType.LAZY
- 연관된 엔티티를 프록시로 조회한다. 프록시를 실제 사용할 때 초기화하며 데이터베이스를 조회한다.
- 지연 로딩을 사용하려면 연관관계를 FetchType.LAZY로 지정한다. EAGER와 마찬가지로 Default값이 LAZY인 경우도 있지만 잘모르겠다면 명시적으로 @ManyToOne(fetch = FetchType.LAZY)로 작성해주자.
- 조회 대상이 영속성 컨텍스트에 존재한다면 프록시 객체를 사용할 이유가 없다. 따라서 영속성 컨텍스트에 이미 로딩이 되어 있다면 프록시 객체가 아닌 엔티티(실제 객체)를 사용한다.
=> 위의 말이 나온 이유는, FetchType=LAZY로 설정을 하게 되면 지연로딩의 대상이 된 쪽은 프록시 객체로 가져오게 된다. 후에 해당 대상을 실제 사용할 때에 초기화가 진행된다.
위에 Default 값에 명시해줬듯이 XToMany의 기본 속성은 LAZY로 설정되어 있다.
❕무슨 소리인지 잘모르겠다면 우선은 FetchType=LAZY로 설정해주자.
LAZY의 경우에도 EAGER에서 발생할 수 있는 문제가 발생하지 않는 것은 아니지만, N+1 문제의 경우에는 fetch join과 Entity Graph 등으로 해결할 수 있다.
'책벌레와 벌레 그 사이 어딘가 > 개념쌓기' 카테고리의 다른 글
[개념쌓기] Fetch Join (0) | 2023.01.04 |
---|---|
[개념쌓기] N+1 문제 (0) | 2023.01.02 |
[개념쌓기] 오버로딩&오버라이딩 (0) | 2022.12.31 |
[개념쌓기] RDBMS & NoSQL (0) | 2022.12.30 |
[개념쌓기] WAS & WS (0) | 2022.12.28 |
댓글