[Spring] JPA - 프록시(Proxy)

2025. 8. 29. 18:24·Back end/Spring Project
반응형

1. em.find() vs em.getReference()

엔티티를 조회할 때 JPA는 두 가지 방식을 제공합니다.

  • em.find() ➡️ 즉시 로딩
    • 데이터베이스를 통해 실제 엔티티 객체를 바로 조회합니다.
    • 즉시 쿼리가 실행됩니다.
  • em.getReference() ➡️ 지연 로딩을 위한 가짜 객체(프록시) 반환
    • 데이터베이스 조회를 미루는 프록시 객체를 반환합니다.
    • 필요할 때까지 쿼리가 실행되지 않고 대기합니다.

2. 프록시란?

프록시 객체는 JPA가 내부적으로 만들어 주는 가짜 객체입니다.
하지만 실제 엔티티 클래스를 상속받아서 만들어지기 때문에 겉으로 보기에는 동일합니다.


3. 프록시의 동작 원리

프록시 객체는 내부적으로 실제 엔티티를 참조(target)로 보관합니다.

  • 프록시 객체를 호출하면 → 실제 엔티티의 메소드를 대신 호출해줍니다.
  • 처음 사용되는 시점에 DB 조회가 발생하면서 초기화 됩니다.
Member member = em.getReference(Member.class, "id1");

// 아직 DB 조회 X
String name = member.getName(); 
// 이 시점에 쿼리 실행 → 프록시 초기화

4. 프록시의 특징과 주의사항

프록시는 편리하지만 몇 가지 주의해야 할 특징이 있습니다.

  1. 초기화는 한 번만 일어난다.
    • 프록시는 처음 접근할 때만 DB 조회가 일어나며, 이후에는 캐싱된 엔티티를 사용합니다.
  2. 프록시가 실제 엔티티로 바뀌는 것은 아니다.
    • 초기화되더라도 여전히 프록시 객체입니다.
    • 따라서 == 비교 시 주의해야 하며, 타입 체크는 instanceof를 사용하는 것이 안전합니다.
  3. 영속성 컨텍스트에 엔티티가 이미 존재하면 실제 엔티티 반환.
    • em.getReference()를 호출하더라도 이미 1차 캐시에 있으면 실제 엔티티를 반환합니다.
  4. 준영속 상태에서 문제 발생
    • 프록시는 영속성 컨텍스트의 도움을 받아야 동작합니다.
    • 만약 준영속(detached) 상태에서 초기화하면 Hibernate는 LazyInitializationException을 던집니다.

💥 LazyInitializationException 발생 상황 예제

import jakarta.persistence.*;
import org.hibernate.Hibernate;

public class ProxyDetachExample {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("examplePU");
        EntityManager em = emf.createEntityManager();

        em.getTransaction().begin();

        // 1. Member 엔티티 저장
        Member member = new Member();
        member.setId("id1");
        member.setName("홍길동");
        em.persist(member);

        em.getTransaction().commit();
        em.clear();

        // 2. 프록시 객체 조회 (DB 조회 안 함)
        Member proxy = em.getReference(Member.class, "id1");
        System.out.println("프록시 클래스 = " + proxy.getClass()); 
        // 출력 예: class com.example.Member$HibernateProxy$....

        // 3. 영속성 컨텍스트 종료 → 준영속 상태
        em.close();

        // 4. 준영속 상태에서 프록시 초기화 시도
        try {
            System.out.println("프록시 이름 = " + proxy.getName()); // ❌ 예외 발생
        } catch (Exception e) {
            e.printStackTrace();
        }

        emf.close();
    }
}

실행 결과

프록시 클래스 = class com.example.Member$HibernateProxy$...
org.hibernate.LazyInitializationException: could not initialize proxy [com.example.Member#id1] - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:170)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:310)
    at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:45)
    ...

즉, 영속성 컨텍스트가 닫힌 상태에서 프록시가 DB 조회를 시도했기 때문에 예외가 발생한 것입니다.


5. 프록시 확인 방법

실무에서는 프록시 객체를 다루다가 “이게 진짜 엔티티인지 프록시인지” 확인해야 할 때가 있습니다.
이때는 아래 방법들을 활용할 수 있습니다.

  • 초기화 여부 확인
    • PersistenceUnitUtil.isLoaded(entity);
  • 클래스 이름 확인
    • System.out.println(entity.getClass().getName()); // ...javasist... or HibernateProxy...
  • 프록시 강제 초기화
    • org.hibernate.Hibernate.initialize(entity);
반응형

'Back end > Spring Project' 카테고리의 다른 글

[SpringBoot] SQL 쿼리 파라미터 로그 남기는 방법  (0) 2026.01.02
[Spring] JPA - @MappedSuperclass  (0) 2025.08.27
[Spring] JPA 양방향 연관관계와 연관관계의 주인  (0) 2025.08.20
[Spring] JPA 준영속 상태(Detached)  (0) 2025.08.15
[Spring] JPA flush  (0) 2025.08.14
'Back end/Spring Project' 카테고리의 다른 글
  • [SpringBoot] SQL 쿼리 파라미터 로그 남기는 방법
  • [Spring] JPA - @MappedSuperclass
  • [Spring] JPA 양방향 연관관계와 연관관계의 주인
  • [Spring] JPA 준영속 상태(Detached)
Kim-SooHyeon
Kim-SooHyeon
개발일기 및 알고리즘, 블로그 운영에 대한 글을 포스팅합니다. :) 목표: 뿌리 깊은 개발자 되기
    반응형
  • Kim-SooHyeon
    soo_vely의 개발로그
    Kim-SooHyeon
  • 전체
    오늘
    어제
    • 분류 전체보기 (255) N
      • 알고리즘 (108)
        • 자료구조 (3)
        • Java (104)
        • Python (1)
      • Back end (71) N
        • Spring Project (28) N
        • Java (21)
        • API (1)
        • Python (0)
        • Django (3)
        • Linux (1)
        • 서버 (2)
        • 에러로그 (11)
        • 부스트 코스 (1)
      • Front end (9)
        • HTML, CSS (4)
        • JavaScript (4)
        • JQuery (0)
      • 기타 프로그래밍 (4)
        • Android Studio (1)
        • Arduino (2)
        • Azure Fundamental(AZ-900) (1)
      • 개발도구 (24)
        • IntelliJ (2)
        • Git (12)
        • SVN (0)
        • Eclipse (2)
        • 기타 Tool (8)
      • Database (16)
        • Oracle (10)
        • MySQL (0)
        • H2 Database (3)
        • ORM & JPA (1)
      • 자격증 (10)
        • 컴활 1급 (7)
        • 컴활 2급 (2)
        • SQLD (1)
      • 기타 (13)
        • 블로그 운영 (6)
        • 문서 (1)
        • 기타 (6)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    jpa
    오라클
    백준알고리즘
    단계별풀기
    for문
    solved.ac
    알고리즘
    springboot
    배열
    1차원 배열
    github
    백준
    구현
    spring
    Git
    백준 자바
    문자열
    Oracle
    java
    BOJ
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Kim-SooHyeon
[Spring] JPA - 프록시(Proxy)
상단으로

티스토리툴바