JPA

즉시 로딩과 지연 로딩

salmon16 2023. 8. 30. 21:51

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을 해서 데이터를 받아온다

em.find(Member.Class, "1"); 했을 때 나오는 SQL 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