JPA 연관 관계 - 프록시 객체

목차

프록시 객체의 특징

  • 실제 클래스를 상속 받아서 만들어진다.
  • 실제 클래스와 겉 모양이 같다.
  • 사용자 입장에서는 진짜 객체인지 프록시 객체인지 구분하지 않고 사용하면 된다.
  • 프록시 객체는 실제 객체의 참조를 보관한다.
  • 프록시 객체를 호출하면 프록시 객체는 실제 객체의 메소드를 호출한다.

프록시 객체

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

em.find() vs em.getReference()

  • em.find()
    • 데이터 베이스를 통해 실제 엔티티 객체를 조회한다.
  • em.getReference()
    • 데이터 베이스 조회를 미루는 가짜(프록시) 엔티티 객체 를 조회한다.
public class JpaMain {
public static void main(String[] ars) {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("hello");
EntityManager em = entityManagerFactory.createEntityManager();
EntityTransaction transaction = em.getTransaction();

transaction.begin();
try {
Member member = new Member();
member.setUsername("hello");

em.persist(member);

em.flush();
em.clear();

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

transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
em.close();
}
entityManagerFactory.close();
}

private static void printMember(Member member){
System.out.println("member = " + member.getUsername());
}

private static void printMemberAndTeam(Member member) {
String username = member.getUsername();
System.out.println("username = " + username);

Team team = member.getTeam();
System.out.println("team = " + team.getName());
}
}
Share