프록시(Proxy)

Soyun_p·2025년 4월 10일
0

📖 지식

목록 보기
9/10
post-thumbnail

🪼 지연 로딩(Lazy Loading)이란?

  • 엔티티가 실제 사용될 때까지 데이터베이스 조회를 지연하는 방법
  • JPA에서 지연 로딩 기능을 사용하려면 실제 객체 대신 프록시 객체를 사용해야 한다

🪼 프록시란?

  • JPA가 실제 엔티티 대신 만들어주는 가짜 객체
  • 실제 클래스를 상속받아서 생성되므로 외형은 동일
  • 실제 데이터가 필요한 시점에 DB 조회 후 실제 객체를 초기화

🪼 프록시 사용 방법

EntityManager.find()

  • 바로 DB 조회 후 실제 엔티티 반환
  • 영속성 컨텍스트에 엔티티가 없으면 데이터베이스를 조회

EntityManager.getReference()

Member member = em.getReference(Member.class, "id1");
member.getName(); //이 시점에 DB 조회
  • DB 조회를 미루고 프록시 객체 반환

🪼 프록시 초기화 흐름

class MemberProxy extends Member{
	Member target = null; //실제 엔티티 참조
	
	public String getName(){
		if(target == null){
			// 1. 프록시 초기화 요청
			// 2. DB 조회
			// 3. 실제 엔티티 생성 후 참조 저장
			this.target = ...;
	}
	return target.getName(); //4. 실제 객체 메서드 호출
	}
}

📌 JPA 프록시 객체 초기화 과정 정리

  1. 프록시 객체에서 member.getName() 같은 메서드가 호출된다.
  2. 프록시 객체는 실제 엔티티가 아직 생성되지 않은 경우, 영속성 컨텍스트에 초기화 요청을 한다.
  3. 영속성 컨텍스트는 데이터베이스를 조회하여 실제 엔티티 객체를 생성한다.
  4. 프록시 객체는 생성된 실제 엔티티 객체를 내부 멤버 변수(target)에 저장한다.
  5. 이후 프록시는 해당 실제 엔티티 객체의 getName()을 호출하여 결과를 반환한다.

🪼 프록시와 준영속 상태

//MemberProxy 반환
Member member = em.getReference(Member.class, "id1");

em.close(); //영속성 컨텍스트 종료
member.getName(); //준영속 상태 초기화 시도
// ❌ LazyInitializationException  예외 발생
  • 영속성 컨텍스트가 종료되면 프록시 초기화가 불가능
  • 이 상태에서 프록시 메서드 호출 시 예외 발생

🪼 프록시와 식별자

프록시는 식별자(PK) 값은 가지고 있다

Team team = em.getReference(Team.class, "team1"); // 식별자 보관
team.getId(); // 프록시 초기화 없이 id만 조회 가능 
  • @Access(AccessType.PROPERTY)
    • 프록시 객체는 식별자 값을 가지고 있으므로 식별자 값을 조회하는 team.getId()를 호출해도 프록시를 초기화하지 않는다 ⇒ 그래서 id만 조회할 때는 N+1 문제가 발생하지 않는다
  • @Access(AccessType.FIELD)
    • JPA는 getId() 메서드가 id 만 조회하는 메서드인지 다른 필드까지 활용해서 어떤 일을 하는 메서드인지 알지 못하므로 프록시 객체를 초기화한다

🪼 프록시로 연관관계 설정하기

프록시는 연관관계를 설정할 때 유용하게 사용할 수 있다

Member member = em.find(Member.class, "member1");
Team team = em.getReference(Team.class, "team1"); //SQL을 실행하지 않음
member.setTeam(team); //식별자만 사용 -> DB 접근 없음
  • 연관관계 설정 시 식별자만 필요하므로 굳이 실제 객체를 조회하지 않아도 된다 -> 성능 최적화

출처: 자바 ORM 표준 JPA 프로그래밍(김영한)

0개의 댓글