JPA

[JPA 18] 프록시(Proxy)

snowkit 2022. 3. 11. 12:46

프록시란?

  • 사전적 정의: 대리, 대리인

Hibernate 프록시

  • JPA 표준 스펙에 프록시와 관련된 내용은 없다
  • JPA의 구현체인 Hibernate의 기능

사용 이유

  • DB에서 Member 테이블만 조회할 때 의미 없이 다른 테이블 JOIN을 걸지 않듯이, JPA에서도 Member만 조회할 때 Team을 같이 조회한다면 성능 면에서 손해
  • 무의미한 쿼리를 줄여 성능을 향상시키기 위해 사용한다

Hibernate 프록시 작동 방식

  • entityManager.find(): 실제 Entity 쿼리
  • entityManager.getReference(): 프록시 객체를 통한 쿼리
  • Hibernate 프록시는 실제 Entity를 상속받는다
    • 타입 체크할 때 ==로 비교하면 실패하므로 instanceof로 비교
  • 프록시 객체 내부에는 상속받은 원본 Entity 필드(비어있음)가 존재한다
    • 처음으로 프록시 객체를 사용하는 시점(getter 등으로 ID를 제외한 필드를 호출하는 시점)에 원본 Entity가 초기화된다
    • 비어있는 Entity 필드에 DB에서 쿼리한 Entity 연결
    • 이후 프록시 객체는 DB에서 쿼리한 Entity 객체 참조
    • 실제 Entity 객체에 접근 가능
    • (중요) 프록시 객체가 영속성 컨텍스트의 관리를 벗어났을 때 초기화하면 LazyInitializationException 발생
      • 프록시 객체가 영속 상태가 아니게 된 경우
      • 영속성 컨텍스트가 닫힌 경우
  • 영속성 컨텍스트에 이미 Entity가 있으면 getReference()를 사용해도 실제 Entity 반환
    • 이미 1차 캐시에 Entity가 들어있는데 프록시를 쓸 이유가 전혀 없기 때문
    • JPA에서 하나의 트랜잭션 내에서 조회한 같은 객체는 == 으로 비교했을 때 true가 나와야 함
  • 영속성 컨텍스트에 프록시가 먼저 올라가 있으면 find()를 사용해도 프록시 반환
    • JPA에서 하나의 트랜잭션 내에서 조회한 같은 객체는 == 으로 비교했을 때 true가 나와야 함

프록시 확인, 초기화

  • 프록시 인스턴스 초기화 여부 확인
    • entityManagerFactory.getPersistenceUnitUtil().isLoaded(entity)
  • 프록시 클래스 확인
    • entity.getClass().getName()
  • 프록시 강제 초기화
    • Hibernate.initialize(entity)
    • JPA 표준 기능이 아닌 Hibernate의 기능