Study/JPA

[JPA] 프록시와 연관관계

lsh2613 2023. 9. 8. 20:18

지연로딩

프록시를 사용하면 사용하지 않는 연관관계 엔티티에 대해 미리 조회하지 않기 때문에 성능을 향상시킬 수 있다.
이것을 지연로딩이라 한다.

반대로 연관된 엔티티를 미리 조회하는 것을 즉시로딩이라 한다.

 

프록시 객체

지연 로딩 기능을 사용하려면 실제 엔티티 객체 대신에 데이터베이스 조회를 지연할 수 있는 가짜 객체가 필요하다.
이를 프록시 객체라 한다.

프록시 객체를 사용하는 방법 이외에도 바이트코드를 수정하는 방법도 존재하지만 여기선 프록시만 다룰 예정이다.

 

EintityManger의 find() 메소드를 사용하면 바로 데이터베이스를 조회하게 된다. 그럼 프록시 객체는 어떻게 사용할까?

EintityManger.getReference()를 사용하면 데이터베이스를 조회하지 않고 실제 엔티티 객체도 생성하지 않는다. 대신 데이터베이스 접근을 위임한 프록시 객체를 반환해준다.

 

프록시 객체의 특징

  • 실제 클래스를 상속 받아서 만들어져서 사용자 입장에서는 진짜 객체인지 프록시 객체인지 구분하지 않고 사용하면 된다
    • 실제 객체에 대한 참조를 보관하고 있어 프록시 객체의 메소드를 호출하면 실제 객체의 메소드를 호출한다.
  • 프록시 객체가 실제 사용될 때 데이터베이스를 조회해서 실제 엔티티 객체를 생성한다.
    • 이것을 프록시 객체의 초기화라 한다
  • 프록시 객체는 처음 사용할 때 한번만 초기화된다.
    • 초기화된다고 해서 프록시 객체가 실제 엔티티로 바뀌는 것은 아니다
    • 단지 프록시 객체를 통해 실제 엔티티를 접근할 수 있다
  • 영속성 컨텍스트에 찾는 엔티티가 이미 있다면 getReference()를 호출해도 프록시가 아닌 실제 객체를 반환한다

 

프록시 초기화

 

주의사항

위 과정을 보면 프록시 객체는 실제 사용될 때 영속성 컨텍스트를 통해 DB에서 값을 조회하여 실제 엔티티를 생성하고 해당 객체에서 값을 조회한다.

이 말은 영속성 컨텍스트가 없다면 불가능하다는 이야기다. 즉, 준영속 상태의 객체에서 값을 조회하게 되면 에러가 발생한다.

// Member Proxy 반환
Member member = em.getReference(Member.class, "id1");
transaction.commit();
em.close() // 영속성 컨텍스트 종료, member -> 준영속 엔티티

member.getName(); // 에러, 준영속 상태 초기화 시도

 

프록시와 식별자

엔티티를 프록시로 조히할 때 식별자(PK) 값을 파라미터로 전달하는데 프록시 객체는 이 식별자 값을 보관한다.

Member member = em.getReference(Member.class, "id1"); // 식별자 보관
member.getId() // 초기화되지 않음