[JPA] 8. 프록시와 연관관계 관리 - 프록시

DAUN JO·2021년 11월 9일
0

JPA

목록 보기
6/11
post-thumbnail

[JPA] 8. 프록시와 연관관계 관리

자바 ORM 표준 JPA 프로그래밍 공부 기록



👀 프록시와 즉시 로딩, 지연 로딩

프록시를 사용하면 연관된 객체를 처음부터 데이터베이스에서 조회하는 것이 아니라 실제 사용하는 시점에 데이터베이스에서 조회할 수 있따. 자주 사용하는 객체들은 조인을 사용하여 함께 조회하는 것이 효과적일 수도 있다. JPA는 즉시 로딩지연 로딩으로 이 둘을 모두 지원한다.




📍 8.1 프록시

엔티티를 조회 할 때 연관된 엔티티들이 항상 사용되는 것은 아니다. 비즈니스 로직에 따라 연관된 엔티티가 사용될 때도, 그렇지 않을 때도 있다.

JPA는 이런 문제를 해결하기 위해 엔티티가 실제 사용될 때 까지 DB 조회를 지연하는 방법을 제공하는데 이것을 지연 로딩이라고 한다.


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


em.find() vs em.getReference()

  • em.find() : 엔티티 조회. 영속성 컨텍스트에 엔티티가 없다면 DB를 조회
  • em.getReference() : DB를 조회하지 않고 실제 엔티티 객체 생성 X. DB 접근을 위임한 프록시 객체 반환

💭 프록시 특징

  • 실제 클래스를 상속받아서 만들어짐
  • 실제 클래스와 겉 모양이 같다
  • 사용하는 입장에서는 진짜 객체인지 프록시 객체인지 구분하지 않고 사용하면 됨
  • 실제 객체의 참조를 보관
  • 프록시 객체의 메소드를 호출하면 실제 객체의 메소드를 호출

💭 프록시 객체의 초기화

Member findMember = em.getReference(Member.class, m.getId());
//System.out.println(findMember.getClass());
//System.out.println(findMember.getId());
System.out.println(findMember.getUserName());

  1. findMember.getUserName() 호출해서 실제 데이터 조회
  2. 실제 엔티티가 생성되어 있지 않으면 영속성 컨텍스트에 초기화 요청 (엔티티 생성 요청)
  3. 영속성 컨텍스트가 DB를 조회에서 실제 엔티티 생성
  4. 프록시 객체는 생성된 엔티티 객체의 참조를 Member target 멤버변수에 보관
  5. 프록시 객체는 실제 엔티티 객체의 getUserName()을 호출해서 결과를 반환한다.

프록시의 특징

  • 처음 사용할 때 한 번만 초기화 (2번 불가능)
  • 프록시 객체를 초기화 할 때 프록시 객체가 실제 엔티티로 바뀌는 것은 아님. 프록시 객체가 초기화 되면 프록시 객체를 통해서 실제 엔티티에 접근 가능

  • 프록시 객체는 원본 엔티티를 상속 받으므로 타입 체크시 주의해야함 ( == 비교 대신에 instance of 사용)

Member findMember1 = em.getReference(Member.class, m.getId());
System.out.println(findMember1.getClass() == Member.class); //false
System.out.println(findMember1 instanceof Member); //true

  • 영속성 컨텍스트에 찾는 엔티티가 이미 있으면 DB를 조회할 필요가 없으므로 em.getReference()를 호출해도 실제 엔티티 반환
Member findMember1 = em.find(Member.class, m.getId());
Member findMember2 = em.getReference(Member.class, m.getId());
System.out.println(findMember1.getClass());
System.out.println(findMember2.getClass());
// 출력 => 둘다 엔티티 반환
class com.jpa.db.Member
class com.jpa.db.Member

  • 준영속 상태일 때, 프록시를 초기화하면 예외 발생 ( 영속성 컨텍스트가 초기화 불가능 )
em.detach(findMember1);
System.out.println(findMember1.getUserName());
//커넥션 에러
org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop


💭 프록시 확인

PersistenceUnitUtil().isLoaded() : 프록시 인스턴스의 초기화 여부 확인

Member refMember = em.getReference(Member.class, m.getId());
//System.out.println(refMember.getClass());
System.out.println(emf.getPersistenceUnitUtil().isLoaded(refMember));

초기화 되지 않았을 경우 false 반환. 이미 초기화 되었거나 프록시 인스턴스가 아닐 경우 true 반환

profile
🍕

0개의 댓글