본문 바로가기
프로그래밍/Back-end

JPA 지연로딩 즉시로딩 프록시 proxy

by @GodWin 2024. 10. 17.

-

 

-

안녕하세요? 오늘은, JPA의 연관관계 관리 중, 프록시( proxy )에 대해서 알아보도록 하겠습니다.

 

 

프록시란?


: JPA에서는 불필요한 쿼리를 최적화하기 위해서는, 지연로딩과 프록시라는 개념으로 해결

※ 지연로딩은, 다음 포스팅에 다뤄보도록 하겠습니다.
※ 해당 포스팅은, 즉시로딩과 지연로딩의 매커니즘의 이해를 돕기위한, 개념 지원 포스팅 입니다.


* find()
: DB를 통해서 실제 엔티티를 바로 조회

* getReference()
: DB 조회를 미루는 가짜(프록시) 엔티티 객체 조회



+
getReference() 가 실행 되었을 때, 프록시 객체는 실제 객체의 참조(target)을 보관한다.
프록시 객체를 호출 시, 프록시 객체는 실제 객체의 메소드를 호출하게 된다.


샘플소스)

EntityManagerFactory emf = Persistence.createEntityManagerFactory("유닛명");
EntityManager em = emf.createEntityManager();

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

EntityA entityA1 = new EntityA();
entityA1.setName("entityA1_1");
em.persist(entityA1);

EntityA entityA2 = new EntityA();
entityA2.setName("entityA2_1");
em.persist(entityA2);

EntityA entityA3 = new EntityA();
entityA3.setName("entityA3_1");
em.persist(entityA3);

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

// 엔티티 객체 비교
EntityA findEntityA1 = em.find(EntityA.class, entityA1.getId());
EntityA findEntityA2 = em.find(EntityA.class, entityA2.getId());

System.out.println("findEntityA1 == findEntityA2 : "
    + (findEntityA1.getClass() == findEntityA2.getClass()));

// 프록시 객체 비교
EntityA findEntityA3 = em.getReference(EntityA.class, entityA3.getId());

System.out.println("findEntityA1 == findEntityA3 : "
    + (findEntityA1.getClass() instanceof findEntityA3.getClass()));

// 영속성 컨텍스트에 엔티티가 존재 시, 프록시 객체가 아닌, 실제 엔티티 반환
EntityA findEntityA4 = em.getReference(EntityA.class, entityA2.getId());

System.out.println("findEntityA2 == findEntityA4 : "
    + (findEntityA2.getClass() == findEntityA4.getClass()));

tx.commit();




+
: 프록시 객체는 처음 사용할 때 한번만 초기화 ★★★
: 프록시 객체를 초기화 할 때, 프록시 객체가 실제 엔티티로 바뀌는 게 아님
> 초기화 되면, 프록시 객체를 통해서 실제 엔티티에 접근 가능
: 프록시 객체는 원본 엔티티를 상속받음
> 타입 체크 시 주의 필요 (== 비교 대신, instance of 사용)
: 영속성 컨텍스트에 찾는 엔티티가 이미 있다면, getReference를 호출해도 실제 엔티티를 반환
: 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태(detach/colse)일 때, 프록시 초기화 시 문제 발생
> LazyInitializationException 발생


※ 보통 실무에서는, 트랜잭션이나 영속성 컨텍스트를 끝내고, 프록시를 조회 시, 해당 내용을 자주 만나게 될 것이다.

 

프록시 확인 방법

: 프록시 인스턴스의 초기화 여부 확인

> emf.PersistenceUnitUtil.isLoaded(엔티티)

: 프록시 클래스 확인 방법

> 엔티티.getClass().getName()

: 프록시 강제 초기화

> Hibernate.initialize(엔티티)

※ JPA 표준에서는, 강제 초기화란 없다.

: 강제호출

> 엔티티.get속성명()



-
오늘은, JPA의 연관관계 관리 중, 프록시에 대해서 알아보았습니다.
그럼 오늘도 즐거운 하루 되시길 바라겠습니다.