인프런 김영한님 강의를 바탕으로 정리한 내용입니다.
실제 클래스를 상속받아서 만들어지며, 실제 클래스와 겉 모양이 같다
프록시 객체가 초기화된다고 해서, 프록시 객체가 실제 엔티티로 바뀌는 것이 아니다.
프록시 객체를 통해, 실제 엔티티로 접근 가능한 것일 뿐임!!
→ .class 등 타입 체크 시 주의 요망 (instance of 등으로 체크하는 것이 바람직)
영속성 컨텍스트에 찾는 엔티티가 이미 있으면 em.getReference()를 호출해도 실제 엔티티가 반환됨
EntityManager.clear() 되어있는 상황에서, 동일한 id로 각 메서드를 호출한다고 가정
find() 호출 후, getReference() 호출
//em = EntityManager
Member findMember = em.find(Member.class, id);
Member referenceMember = em.getReference(Member.class, id);
System.out.println(findMember.class);
System.out.println(referenceMember.class);
System.out.println(findMember == referenceMember);
/*
result:
Member
Member
true
*/
find()가 실행될 때 영속성 콘택스트에 등록이 된 상태임으로, getReference()를 실행해도 1차 캐시에서 바로 조회해 오기 때문에 위와 같은 결과가 나오게 됩니다.
getReference() 호출 후, 다시 getReference() 호출
Member referenceMember1 = em.getReference(Member.class, id);
Member referenceMember2 = em.getReference(Member.class, id);
System.out.println(referenceMember1.class);
System.out.println(referenceMember2.class);
System.out.println(findMember == referenceMember);
/*
result:
MemberProxy
MemberProxy
true
*/
마찬가지로, 2번째 조회 시 영속성 콘택스트에 등록된 프록시 객체를 가져오게 됩니다.
getReference() 호출 후, find() 호출
Member referenceMember = em.getReference(Member.class, id);
Member findMember = em.find(Member.class, id);
System.out.println(referenceMember.class);
System.out.println(findMember.class);
System.out.println(findMember == referenceMember);
/*
result:
MemberProxy
MemberProxy
true
*/
Spring에서는 동일성을 보장하기 위해, 영속성 콘택스트에 프록시 객체가 먼저 등록된 경우
find() 호출 시에도 프록시 객체를 반환합니다!
위에서 다루었던 프록시를 디폴트로 켜주는 것
지연 로딩으로 설정하면, find()를 호출해도 프록시 객체가 생성된다.
@ManyToOne, @OneToOne(ToOne류 매핑)은 기본이 즉시 로딩
하지만 빈번하게 같이 사용하는 Entity들을 매핑할 때는 즉시 로딩 (Eager loading)이 더 바람직하다.
즉시로딩을 사용하면 전혀 예상하지 못한 SQL이 등장할 가능성이 있다
find() 한 번 불렀는데, select 쿼리가 10개씩 나갈 수도 있는 것
JPQL에서 N+1 문제를 일으킨다
1의 작업을 실행했는데, N의 실행이 따라오는 것 (매우매우매우 지양해야 할 상황!)
ex) JPQL로 member 리스트를 호출할 때, 매핑된 테이블이 즉시 로딩으로 설정된 상황
List<Member> members =
em.createQuery(”select m from Member m”, Member.class)
.getResultList()
이 상황에서 JPQL이 작성하는 쿼리는 SELECT * FROM MEMBER (1)
때문에 Member 테이블의 row 하나 당 Team을 조회하는 쿼리가 날아간다 (N)
→ N+1 문제 발생