[Spring] Proxy

이연우·2025년 8월 19일

TIL

목록 보기
87/100

🔎 Entity 조회

🧩 왜 프록시를 쓸까?

  • 지연 로딩(Lazy Loading)으로 불필요한 SELECT를 미룸
    → 실제로 속성에 접근하는 “그 순간”에 쿼리 실행

  • 연관 엔티티를 항상 같이 가져오지 않아도 됨
    N+1 줄이기/튜닝 전략과 함께 사용

📌 예제: TutorCompany 관계

Tutor findTutor = em.find(Tutor.class, 1L);
System.out.println(findTutor.getName()); // Tutor 조회
System.out.println(findTutor.getCompany().getName()); // Company까지 접근 시 추가 SQL
  • Tutor만 필요하다면 굳이 Company까지 바로 조회할 필요 ❌
  • 그래서 프록시를 활용하면 효율적으로 필요한 시점에만 조회 가능

⚔️ em.find() vs em.getReference()

  • em.find(Entity.class, id)
    즉시 DB 조회진짜 엔티티 반환

  • em.getReference(Entity.class, id)
    DB 조회 없이 프록시 반환 (필드 접근 시점에 초기화/SELECT)

💡 동일 영속성 컨텍스트에 이미 1차 캐시에 있으면 두 메서드 모두 실제 엔티티 반환 (추가 SELECT 없음)

Tutor proxyTutor = em.getReference(Tutor.class, tutor.getId());
System.out.println(proxyTutor.getClass());
// => Hibernate Proxy 클래스

🤖 Proxy

🧩 Proxy 객체란?

  • JPA가 지연 로딩(Lazy Loading)을 지원하기 위해 만드는 대리 객체
  • 📦 Proxy = 진짜 엔티티 대신 쓰이는 껍데기 객체
  • Proxy 내부에는 실제 엔티티(target)에 대한 참조가 들어 있음
  • 실제 값이 필요할 때 DB 조회 후 target을 초기화해서 사용

⚙️ 프록시 초기화 흐름

  1. em.getReference()로 프록시 획득

  2. 프록시의 메서드(예: getName()) 호출

  3. 영속성 컨텍스트에 초기화 요청

  4. DB 조회 수행

  5. 실제 엔티티 생성/연결

  6. 이후엔 실제 엔티티에 위임 (초기화는 보통 한 번만)

⚡ Proxy 특징

  • 최초 접근 시 한 번만 초기화
    이후에는 같은 엔티티로 계속 접근 가능

  • 프록시 객체로 실제 엔티티에 접근 가능

  • 이미 영속성 컨텍스트에 엔티티가 있다면
    getReference() 해도 프록시 대신 실제 엔티티 반환

  • ⚠️ 주의: 준영속 상태에서 Proxy 접근 → LazyInitializationException 발생
    (영속성 컨텍스트의 도움이 없어서 DB 접근 불가)

Tutor proxyTutor = em.getReference(Tutor.class, tutor.getId());
em.detach(proxyTutor); // 준영속 상태

proxyTutor.getName();  // ❌ LazyInitializationException 발생

🧠 요약 정리

구분em.find() 🔍em.getReference() 🎭 (Proxy)
조회 방식즉시 DB 조회 (SQL 실행)Proxy 객체(가짜 엔티티) 반환
반환 객체실제 엔티티Proxy 객체 (Hibernate가 실제 엔티티 클래스를 상속해 생성)
DB 조회 시점em.find() 호출 시 바로 실행Proxy 속성/메서드 최초 접근 시 실행
초기화필요 없음최초 한 번만 초기화, 이후 같은 엔티티 사용
내부 구조엔티티 자체Proxy 내부에 target(실제 엔티티 참조) 보관
비교 특징실제 엔티티이므로 == 비교 가능Proxy와 실제 엔티티 == 비교는 실패 ❌
instanceof 비교는 가능 ⭕
장점즉시 조회가 필요한 경우 적합지연 로딩(Lazy Loading) 가능 → 성능 최적화
주의 사항항상 SQL 실행
→ 불필요한 조회 발생 가능
준영속 상태에서 접근 시 LazyInitializationException ⚠️
잘못 사용 시 N+1 문제 발생

0개의 댓글