다음과 같은 상황이 있다
💡 이때, 지연로딩을 사용한다면 ?
이러한 지연로딩이라는 기술을 가능하게 하는 것이 프록시이다
em.find() 데이터베이스를 통하여 실제 엔티티 객체를 조회
em.getReference() 데이터베이스 조회를 미루는 가짜(프록시) 엔티티 객체 조회
Member findMember = em.getReference(Member.class, member.getId()); //프록시 조회
System.out.prinln("findMember.id = " + findMember.getId()); //쿼리X
System.out.prinln("findMember.username = " + findMember.getUsername()); //쿼리O
프록시는
Member member = em.getReference(Member.class, “id1”); //프록시 객체
member.getName(); //호출

순서
프록시 호출 (처음엔 target 값이 없음)
-> 영속성 컨텍스트에 값 요청 (초기화 요청)
-> DB를 조회하여 실제 Entity 생성
-> target과 Entity 연결
처음 한 번만 초기화
초기화 시, 프록시 객체가 실제 엔티티로 바뀌는 것이 아님
초기화되면 프록시 객체를 통해 실제 엔티티로 접근
프록시 객체는 원본 엔티티를 상속
👉 JPA Entity 타입 비교시 == 가 아닌 instance of 사용
JPA는 같은 영속성 컨텍스트 안에서 == (참조값) 비교시 true를 보장 (동일성 보장)
👉 찾는 엔티티가 이미 영속성 컨텍스트에 있으면 em.getReference() 를 호출해도 실제 엔티티를 반환
👉 한 번 em.getReference()로 조회하면 이후 em.find()로 조회해도 프록시 객체 반환
준영속 상태일 때, 프록시를 초기화하면 문제 발생 (hibernate : LazyInitializationException)
ex) em.clear , em.detach, em.close 후 초기화
PersistenceUnitUtil.isLoaded(Object entity)emf.getPersistenceUnitUtil().isLoaded()
프록시 클래스 확인 방법
entity.getClass.getName()
프록시 강제 초기화
Hibernate.initailize(entity)
Hibernate 제공
JPA 표준은 강제 초기화가 없음
강제 호출 : member.getName()
@ManyToOne, @OneToOne 기본값 즉시 로딩
👉 LAZY로 설정
@OneToMany, @ManyToMany 기본값 지연 로딩
Member , Team 은 자주 함께 사용 👉 즉시 로딩
Member , Order 는 가끔 사용 👉 지연 로딩
Order, Product 는 자주 함께 사용 👉 즉시 로딩
결론!