지연 로딩 기능을 사용하려면 실제 객체 대신 프록시 객체를 사용해야 한다EntityManager.find()
EntityManager.getReference()
Member member = em.getReference(Member.class, "id1");
member.getName(); //이 시점에 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 프록시 객체 초기화 과정 정리
member.getName() 같은 메서드가 호출된다.(target)에 저장한다.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)getId() 메서드가 id 만 조회하는 메서드인지 다른 필드까지 활용해서 어떤 일을 하는 메서드인지 알지 못하므로 프록시 객체를 초기화한다프록시는 연관관계를 설정할 때 유용하게 사용할 수 있다
Member member = em.find(Member.class, "member1");
Team team = em.getReference(Team.class, "team1"); //SQL을 실행하지 않음
member.setTeam(team); //식별자만 사용 -> DB 접근 없음