본문 바로가기
JPA

프록시와 연관관계 관리

by Heesu.lee 2021. 1. 20.

프록시 기초

  • em.find() 와 em.getReference()
  • em.find 의 경우 데이터베이스를 통해서 실제 엔티티 객체 조회
  • em.getReference 의 경우 데이터베이스 조회를 미루는 가짜 프록시 엔티티 객체 조회
    • 사용하는 시점에 실제 쿼리를 요청함

프록시 특징 (1)

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

 

프록시 객체와 진짜 엔티티

프록시 객체의 초기화

  • 실제 엔티티 정보 조회 요청
  • 초기화 요청 → 영속성 컨텍스트
  • 영속성 컨텍스트를 통하여 DB 조회
  • 실제 Entity 생성
  • 해당 Entity (Target) 를 통하여 요청한 정보 획득

프록시 특징 (2)

  • 프록시 객체는 처음 사용할 때 한 번만 초기화
  • 프록시 객체 초기화 시 프록시 객체가 해당 엔티티에 접근이 가능한 것이지 실제 엔티티로 바뀌는 것은 아니다
  • 프록시 객체는 원본 엔티티를 상속 받음, 따라서 타입 체크시 주의 (instance of)
  • 영속성 컨텍스트에 찾는 엔티티가 이미 있다면, em.getReference 를 호출하여도 실제 엔티티를 반환
  • 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화 하면 문제 발생 - LazyInitializationException 예외
한 트랜잭션 안에서 == 비교 값을 true 로 맞추기 위해 필요한 객체를 반환한다.

프록시 확인

  • 프록시 인스턴스의 초기화 여부 확인 - PersistenceUnitUtil.isLoaded(Object entity)
  • 프록시 클래스 확인 방법 - entity.getClass().getName()
  • 프록시 강제 초기화
참고로 JPA 표준은 강제 초기화 없음 따라서, 강제 호출 (실제 정보를 요청)해야 초기화가 된다. - member.getName()

지연 로딩과 프록시

지연 로딩의 경우 엔티티 조회 시 해당 객체를 프록시로 조회한다.

그리고 실제 연관관계 엔티티를 사용하는 시점에 초기화 한다. (DB 조회)

지연 로딩과 프록시

반대로 즉시 로딩의 경우 연관관계 엔티티를 모두 조회해오는 방식

 

프록시와 즉시 로딩 주의

  • 가급적 지연 로딩만 사용하자
  • 즉시 로딩을 적용하면 예상하지 못한 SQL 이 발생
  • 즉시 로딩은 JPQL 에서 N + 1 문제를 일으킨다.
  • @ManyToOne, @OneToOne 은 기본이 즉시 로딩, 지연 로딩으로 바꿔 쓰자
  • 반대로 XtoMany 관계의 경우 기본이 지연 로딩

실무에서 지연 로딩 활용 

  • 모든 연관관계에 지연 로딩을 사용해라
  • 실무에서 즉시 로딩을 사용하지 마라
  • JPQL fetch 조인이나, 엔티티 그래프 기능을 사용해라
※주의 - 즉시 로딩의 경우 정말 상상하지 못한 쿼리가 요청된다.

 

참조

  • 해당 게시글은 김영한님의 "자바 ORM 표준 JPA 프로그래밍 - 기본편" 을 바탕으로 작성되었습니다.

'JPA' 카테고리의 다른 글

쿼리 메소드 기능  (0) 2021.01.26
객체지향 쿼리 언어  (0) 2021.01.25
값 타입  (0) 2021.01.19
상속 관계 매핑  (0) 2021.01.14
다양한 연관관계 매핑  (0) 2021.01.12

댓글