-
[Spring] ProxySpring 2025. 4. 16. 22:20#프록시
💡 Spring 정리: 프록시
📘 개념 정리
Proxy
🎯 JPA에서 엔티티 객체의 지연 로딩(Lazy Loading)을 지원하기 위해 사용하는 대리 객체이다.
🎯 실제 엔티티 객체를 생성하거나 데이터베이스에서 값을 읽어오지 않고도 엔티티의 참조를 사용할 수 있다.
1. 성능향상
진짜 객체를 매번 DB에서 꺼내오면 너무 느리기 때문애 필요할 때만 객체를 생성해서 로딩 해서 효율 UP
2. 연관된 엔티티가 많을 때 특히 유용
회원이 연관된 정보를 한번에 가져오면 속도가 느려진다. 대타로 불려갔다가 그 뒤에 진짜 데이터가 불려온다.(Lazing)
3. 처음에는 느리지만 데이터를 반복 조회할 수록 빨라진다.
동작 속도 초반 조회 DB에 직접 접근 느림 1번 조회 프록시 or 1차 캐시 사용 빠름 반복 조회 DB 쿼리 없음(캐쉬됨) 매우빠름 
✅ Proxy 객체
● proxy객체는 실제 클래스를 상속 받아서 만들어진다.
Member member = em.getReference(Member.class, 1L);em.getReference(Memeber.class, 1L)는 실제 Member가 아닌, Member를 상속한 객체를 반환
실제 DB 접근은 member의 필드에 접근하는 순간 일어난다.

● 데이터 베이스 조회를 지연하는 가짜(Proxy) 객체를 조회한다.
실제 Entity와 == 비교 실패, instanceof 사용
Proxy는 실제 Entity가 아닌 대리 객체이므로, '==' 비교는 실패한다.
대신 'instanceof' 연산자를 사용해야 Proxy 여부를 정확히 판별할 수 있다.✅ Proxy 객체 초기화
1. 유저1 -> 정보를 조회 처음 할 때, 시간이 걸림.
유저2 -> 유저 1과 같은 정보를 조회를 할때 DB를 가지 않고 연속성 컨텍스트를 간다.

🔄 동작 흐름
No 동작 0 em.getReference() 호출 프록시 객체 생성(아직 DB 조회 안 함) 1 프록시 객체의 필드 getName() 접근시 2 JPA가 영속성컨텍스트에 Target 초기화 요청 3 DB에서 실제 데이터를 조회 4 Entity 생성 5 target의 getName() 호출 ✅ Proxy 특징
- 최초로 사용(실제 Entity에 접근)할 때 한 번만 초기화된다.
- 프록시 객체를 통해 실제 Entity에 접근할 수 있다.
- em.getReference() 호출 시 영속성 컨텍스트에 Entity가 존재하면 실제 Entity가 반환된다.
- 준영속 상태에서 프록시를 초기화하면 LazyInitializationException 예외가 발생한다.
Tutor proxyTutor = em.getReference(Tutor.class, tutor.getId()); System.out.println("proxyTutor.getClass() = " + proxyTutor.getClass()); // 준영속 상태 em.detach(proxyTutor); proxyTutor.getName();-
- 실행결과

● detach() : 영속성 컨텍스트가 관리하지 않는다.
● 영속성 컨텍스트를 통해 도움을 받아야만 실제 Entity에 접근이 가능하다.
● 실제 JPA 개발에서 가장 많이 마주치는 Exception
LazyInitializationException은 프록시가 초기화되기 전에
영속성 컨텍스트에서 분리(detach)되면 발생한다.
→ 즉, 지연 로딩 대상 필드를 조회할 때 세션이 닫혀 있으면 에러!✨ 팁 & 인사이트
✅ EntityManager란?
JPA에서 엔티티를 관리하는 핵심 인터페이스
→ 영속성 컨텍스트(Persistence Context)를 통해 엔티티의 상태 변화 감지, DB 반영까지 담당엔티티의 생명 주기, 1차 캐시, 프록시, JPQL 모두 Entity Manager가 조종한다.
🔧 주요 기능 (진짜 자주 쓰는 것만!)
메서드설명persist(entity) 엔티티 저장 (INSERT) find(엔티티.class, id) DB에서 즉시 조회 (실제 객체 반환) getReference(엔티티.class, id) 프록시 객체 반환 (실제 조회 지연됨) remove(entity) 엔티티 삭제 (DELETE) flush() DB와 동기화 (SQL 즉시 실행) clear() 영속성 컨텍스트 초기화 (1차 캐시 제거) detach(entity) 특정 엔티티를 영속성 컨텍스트에서 분리 createQuery(...) JPQL 쿼리 생성 및 실행 핵심 개념: EntityManager는 “영속성 컨텍스트”를 다룬다
상태 의미 비영속 아직 persist() 안 함 → 관리 안 됨 영속 persist() 된 상태 → 1차 캐시에 올라감 준영속 detach() 되거나 clear() 후 → 더 이상 관리되지 않음 삭제 remove()로 삭제 예약 상태
🧪 테스트에서 자주 쓰는 패턴
em.persist(entity); // 저장 em.flush(); // DB 동기화 em.clear(); // 영속성 컨텍스트 초기화 Entity proxy = em.getReference(Entity.class, id); // 프록시로 조회⚠️ 실수 및 주의사항
- persist()는 트랜잭션 커밋 시점에 실제 DB에 반영됨
- find() vs getReference()는 프록시 테스트할 때 차이 반드시 기억
- flush() 없이 createQuery()로 조회하면 변경 내용이 반영 안 될 수 있음.
'Spring' 카테고리의 다른 글
[Spring] 영속성 전이 (Cascade) (0) 2025.04.17 [Spring] 지연로딩, 즉시 로딩 (0) 2025.04.16 [Spring] 연관관계 유형 (0) 2025.04.16 [Spring] 연관관계1 (1) 2025.04.16 [Spring] API 예외 처리 @ExceptionHandler (0) 2025.04.15