8장. 프록시

 프록시

  • 객체는 객체그래프로 연관된 객체들을 탐색한다. 그런데 객체가 데이터베이스에 저장되어 있으므로 연관된 객체를 마음껏 탐색하기는 어렵다.
  • JPA는 이러한 문제를 해결하려고 프록시라는 기술을 사용한다.
  • 프록시는 연관된 객체를 처음부터 데이터베이스에서 조회하는 것이 아니라, 실제 사용하는 시점에 데이터베이스에서 조회할 수 있다. 하지만 자주 함께 사용하는 객체들은 조인을 사용해서 함께 조회하는 것이 효과적이다.
  • JPA는 즉시로딩과 지연 로딩이라는 방법으로 둘을 지원한다.
  • JPA는 연관된 객체를 함께 저장하거나 함께 삭제할 수 있는 영속성 전이와 고아 객체 제거라는 편리한 기능을 제공한다.

 

프록시의 특징

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

 

 📝 프록시 예제

public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try {

            Member member = new Member();
            member.setUsername("kuser");
            em.persist(member);

            Member member2 = new Member();
            member2.setUsername("aa");
            em.persist(member2);

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

            Member findMember = em.find(Member.class, member.getId());
            Member refMember = em.getReference(Member.class, member2.getId());

            System.out.println("findMember = " + findMember.getClass());
            System.out.println("refMember = " + refMember.getClass());
            System.out.println("(findMember == refMember) = " + (findMember == refMember));
            System.out.println("(findMember instanceof Member) = " + (findMember instanceof Member));
            System.out.println("(refMember instanceof Member) = " + (refMember instanceof Member));

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

        emf.close();
    }
}

 📝 결과

findMember = class hellojpa.Member
refMember = class hellojpa.Member$HibernateProxy$PPn3ifLH
(findMember == refMember) = false
(findMember instanceof Member) = true
(refMember instanceof Member) = true

'📚 Spring > Spring JPA' 카테고리의 다른 글

8장. 프록시 - 지연로딩  (0) 2023.08.30
다대일 단반향 - 다대일 양방향  (0) 2023.08.27
[Spring JPA #7] 7장. 고급매핑  (0) 2023.08.26
[정리] 준영속  (0) 2022.03.17
[정리] 플러시 (flush())  (0) 2022.03.16

댓글

Designed by JB FACTORY