Member와 Team이 [N : 1] 연관 관계 매핑이 되어있는 상태에서 Member를 조회할 때 상항 Team을 같이 조회해야 할까?
비즈니스 로직이 단순 Member정보만 사용하는 경우에 Team 테이블도 Join해서 데이터를 가져오면 손해가 발생된다.
LAZY을 사용하여 지연 로딩을 해보자
@Entity
public class Member extends BaseEntity{
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
@ManyToOne 어노테이션 속성으로 fetch = FetchType.LAZY를 사용한다.
이렇게 되면 Member를 조회할 때 team을 프록시로 조회해서 가져온다.
이후 Team에 있는 메서드(team.getName())를 사용하면 메소드 사용시점에 쿼리가 나가 DB에서 데이터를 가져오게 된다.
EAGER을 사용하여 즉시 로딩
위 코드에서 fetch 부분을 EAGER로 바꾸면 즉시 로딩이 된다.
@ManyToOne(fetch = FetchType.LAZY)
즉시 로딩이란 member 조회 시 team 테이블과 join을 해서 데이터를 받아온다
프록시와 즉시로딩 주의
- 가급적 지연 로딩만 사용
- 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생
- find를 할 때 여러 개의 연관관계가 매핑되어 있으면 모든 데이블이 Join된다.
- 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.
- em.createQuery("select m from Member m", Member.class).getResultList();를 하면 select SQL이 2번 전송된다.
- select * from Member -> 멤버를 가져오니 eager이어서 Team 테이블도 가져오는 SQL 작성
- select * from Team where TEAM_ID = xxx
- @ManyToOne, @OneToOne은 기본이 즉시로딩 -> LAZY로 설정해야 한다.
- @OneToMany, @ManyToMany는 기본이 지연로딩
지연 로딩 활용 - 실무
- 모든 연관관계에서 지연 로딩을 사용해라
- 실무에서 즉시로딩을 사용하지 마라
- JPQL fetch 조인이나, 엔티티 그래프 기능을 사용해라
- 즉시 로딩은 상상하지 못한 쿼리가 나간다.
'JPA' 카테고리의 다른 글
기본값 타입 (0) | 2023.08.31 |
---|---|
영속성 전이 : CASCADE, 고아객체 (0) | 2023.08.31 |
프록시와 연관관계 관리 (0) | 2023.08.30 |
MappedSuperclass (0) | 2023.08.30 |
상속관계 매핑 (0) | 2023.08.29 |