[JPA] 프록시와 지연 로딩

2023. 4. 9. 23:47DB/JPA

프록시와 연관관계 관리

객체가 DB에 저장되어 있으므로 연관된 객체를 자유롭게 탑색하기 어렵습니다. JPA 구현체들은 이 문제를 해결하기 위해 프록시라는 기술을 사용합니다.
프록시를 사용하면 연관된 객체를 처음부터 DB에서 조회하는 것이 아니라, 실제 사용하는 시점에 조회할 수 있습니다. 하지만 자주 함께 사용되는 객체들은 조인을 사용해서 함께 조회하는 것이 효과적입니다.

JPA는 즉시 로딩과 지연 로딩이라는 방법으로 둘을 모두 지원합니다.

지연 로딩

Member 객체가 Team 객체를 @ManyToOne으로 참조하고 있을 때, Member 객체가 Team 객체와 관련된 정보를 사용하지 않는다면 연관된 Team 엔티티까지 함께 조회하는 것은 효율적이지 않습니다.

이런 문제를 해결하기 위해 엔티티가 실제 사용될 때까지 DB 조회를 지연하는 방법이 지연 로딩입니다.

JPA 표준 명세는 지연 로딩의 구현 방법을 JPA 구현체에 위임했습니다. 따라서 지금부터의 설명은 하이버네이트 구현체에 대한 내용입니다. 
하이버네이트는 지연 로딩을 지원하기 위해 프록시를 사용하는 방법과 바이트코드를 수정하는 두 가지 방법을 제공하는데 
바이트코드를 수정하는 방법은 설정이 복잡하므로 별도의 설정이 필요 없는 프록시에 대해서만 알아봅니다. 

프록시를 알 수 있는 방법은 두 가지가 있습니다. 영속성에서 인스턴스가 loaded 됐는지 확인하는 getPersistenceUnitUtil().isLoaded() 메소드를 사용하거나, getClass().getName()을 사용해서 $HibernateProxy가 찍힌다면 프록시인지 확인할 수 있습니다.

    void proxyTestWithPersistenceUnitUtilIsLoaded() {
        Member memberProxy = entityManager.getReference(Member.class, 1L);
        boolean isLoadedProxy = entityManager.getEntityManagerFactory().getPersistenceUnitUtil().isLoaded(memberProxy);
        assertThat(isLoadedProxy).isFalse();
        memberProxy.getName();
        boolean isLoaded = entityManager.getEntityManagerFactory().getPersistenceUnitUtil().isLoaded(memberProxy);
        assertThat(isLoaded).isTrue();
    }

이번 시간은 프록시가 지연 로딩에 어떻게 사용되는지 살펴보았습니다. 다음 번엔 지연 로딩에 대해 자세히 알아보겠습니다.