JPA 프록시와 연관관계 관리

프록시

실제 클래스를 상속 받아서 만들어진 가짜 객체
지연로딩의 핵심

프록시 구조

프록시 객체의 초기화

  1. 초기화가 안된 프록시 객체에서 getName()등을 호출
  2. target이 null 이므로 영속성 컨텍스트에 초기화 요청
  3. 영속성 컨텍스트가 해당 엔티티 DB 조회후 영속한뒤 target에 넣어줌
  4. target.getName()을 반환

em.find() vs em.getReference()

프록시의 특징

즉시 로딩과 지연 로딩

JPA에서는 getReference를 통해 프록시를 직접 사용하지 않는다.
대신 즉시 로딩지연 로딩이라는 전략을 설정해 사용한다.

지연 로딩

연관관계 매핑 에노테이션에 fetch를 FetchType.LAZZ로 설정하면
해당 엔티티는 지연 로딩이 된다.
지연 로딩으로 설정하면 조회시 프록시로 반환되고 실제 사용이 이루어져야 DB에서 조회된다.

@Entity
public class Member {

  @Id
  @GeneratedValue
  private Long id;
  
  @Column(name = "USERNAME")
  private String name;
  
  @ManyToOne(fetch = FetchType.LAZY) //**
  @JoinColumn(name = "TEAM_ID")
  private Team team;
  ..
}
Member findMember = em.find(Member.class, 1L);  //member는 DB에서 조회하고 team은 프록시로 반환함
System.out.println(findMember.getClass());      //class x.Member
Team team = findMember.getTeam();               //여기선 초기화 안됨
System.out.println(team.getClass());            ////class x.Team$HibernateProxy$xxxxxxx
team.getName();                                 //초기화됨

즉시 로딩

연관관계 매핑 에노테이션에 fetch를 FetchType.EAGER로 설정하면
해당 엔티티는 즉시 로딩이 된다. 즉시 로딩으로 설정하면 처음 조회시 join을 통해 관련된 모든 엔티티를 가져온다.

JPA 구현체는 가능하면 조인을 사용해 SQL 한번에 함께 조회한다.
일부는 개별 SQL로 조회하는듯 하다.

주의사항
무조건 처음에는 지연 로딩만 사용해야한다.