본문 바로가기
JPA

[JPA] 프록시와 지연로딩

by 민죠미 2023. 5. 19.

본 게시글은 김영한 님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 을 정리한 내용입니다.

 

필요한 연관관계만 조회해 오는 것이 효과적이다

  • JPA를 사용하면 객체 그래프를 통해 연관관계를 탐색할 수 있다
  • 엔티티들은 데이터베이스에 저장되어 있다
    • 한 객체 조회 시 연관되어 있는 엔티티들을 모두 조회하는 것 보다는 필요한 연관관계만 조회해 오는 것이 좋다
    • 이를 위해 JPA는 지연로딩 방식을 지원, 하이버네이트(Hibernate)는 프록시 객체를 통해 지연 로딩을 구현한다

다음과 같은 객체 관계를 가질 때, Member를 조회할 시 Team도 함께 조회해야할까?
단순히 회원 이름만 출력한다면 Team까지 조회 쿼리를 날릴 필요가 없다. 이를 위해 지연로딩을 사용한다.

JPA에서의 프록시

em.find() 와 em.getReference()

  • em.find() : 데이터베이스를 통해서 실제 엔티티 객체 조회
  • em.getReference(): 데이터베이스 조회를 미루는 가짜(프록시) 엔티티 객체 조회

  • 프록시 객체는 실제 클래스를 상속받아 만들어짐
  • 최초 지연 로딩 시점에는 Entity target = null
  • 실제 객체의 메서드를 호출할 필요가 있을 때 데이터베이스를 조회해서 참조 값을 채우게 되는데, 이를 프록시 객체를 초기화한다고 함

 

    Member member = em.getReference(Member.class, “id1”);
    member.getName();

프록시의 특징

  • 프록시 객체는 처음 사용할 때 한 번만 초기화
  • 프록시 객체를 초기화 할 때, 프록시 객체가 실제 엔티티로 바뀌는 것은 아님, 초 기화되면 프록시 객체를 통해서 실제 엔티티에 접근 가능
  • 프록시 객체는 원본 엔티티를 상속받음, 따라서 타입 체크시 주의해야함 (== 비 교 실패, 대신 instance of 사용)
  • 영속성 컨텍스트에 찾는 엔티티가 이미 있으면 em.getReference()를 호출해 도 실제 엔티티 반환
  • 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화하면 문제 발생 (하이버네이트는 org.hibernate.LazyInitializationException 예외를 터트림)

 

지연 로딩 LAZY

@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "USERNAME")
    private String name;

    @ManyToOne(fetch = FetchType.LAZY) //**
    @JoinColumn(name = "TEAM_ID")
    private Team team;

    ...
}

위와 같을 때

Member member = em.find(Member.class, 1L);

Member 조회시 Team 은 조회 쿼리가 생기지 않는다

Team team = member.getTeam();
team.getName(); // 실제 team을 사용하는 시점에 초기화(DB 조회)

team.getName(); 과 같이 실제 Team을 조회해야 할 때 쿼리가 발생한다.

 

즉시로딩은 실무에서 사용하지 않는다

Member와 Team을 자주 함께 사용한다면 즉시로딩을 고려해볼 수 있다. 그러나 즉시로딩은 N+1문제 등 예상하지 못한 SQL이 발생하므로 실무에서 사용하지 않는다.

  • @ManyToOne, @OneToOne은 기본이 즉시 로딩 -> LAZY로 설정
  • @OneToMany, @ManyToMany는 기본이 지연 로딩
  • 즉시로딩 대신 JPQL fetch 조인이나 엔티티 그래프 기능을 사용

 

 

Reference.

  • https://tecoble.techcourse.co.kr/post/2022-10-17-jpa-hibernate-proxy/

댓글