프록시와 연관관계 관리

JooHeon·2021년 11월 15일
0
post-custom-banner

❔ 프록시란?

  • 하이버네이트가 내부적으로 원본 Entity를 상속받아 만든 겉모양이 같은 가짜 객체

🖊 프록시의 특징

  • 프록시 객체는 처음 사용할 때 한 번만 초기화
  • 프록시 객체는 실제 객체의 참조(target)를 보관한다.
  • 프록시 객체의 메소드를 호출하면 프록시 객체는 실제 객체(target)의 메소드를 호출한다.
    (객체 타입 비교시 == 비교 실패, instance of 사용)
  • 프록시 생성시 1차 캐시에 해당 Entity가 있다면 Entity를 반환
    (반대 순서는 Proxy 반환 => 동일 트랜잭션에서는 == 비교가 같음을 보장)
  • 같은 Entity로 프록시를 여러개 생성해도 모두 같은 주소의 프록시다.

🖊 JPA의 프록시 객체 동작방식

  1. Client는 Entity의 메소드를 호출
  2. 프록시 객체는 영속성 컨텍스트에 초기화를 요청
  3. 영속성 컨텍스트는 있는지 확인하고 없으면 DB 조회
  4. 실제 Entity를 생성 및 1차 캐시에 보관
  5. 프록시 객체는 target의 실제 메소드를 호출
    ==> 원본 Entity가 준영속 상태에서 프록시 객체의 메소드를 사용하면 오류발생

🖊 왜 프록시를 써야할까?

연관관계에 있는 Entity의 데이터를 사용 시점에 DB에서 가져오기 위해(지연 로딩)
즉시 로딩은 JPQL에서 N+1문제를 일으켜 권장되지 않는다.

@Entity
public class Member{
    	...
@ManyToOne(fetch = FetchType.EAGER)
RelationalEntity entity;
	...
// find의 경우에는 PK를 통해 JOIN으로 가져온다.(쿼리 1번)
List<Member> members = em.createQuery("select m from Member m", Member.class);
// JPQL은 단순 SQL로 쿼리를 만들어 보내므로 Member Entity를 가져왔을 때(쿼리 1번)
// SQL : SELECT * FROM Member;
// 연관된 Entity를 List에 들어있는 Member size만큼 다시 호출한다(쿼리 N번)
// SQL : SELECT * FROM RelationalEntity WHERE ...
//해결방안 FetchType을 Lazy로 바꾸고 fetch join
List<Member> members = em
	.createQuery("select m from Member m join fetch m.entity, Member.class);
post-custom-banner

0개의 댓글