<aside> ❗

프록시

image.png

[두 가지 경우]

<aside> ❗

프록시 기초

[em.find() VS em.getReference()]

image.png

Member member = new Member();
member.setName("hello");

em.persist(member);

em.flush();
em.clear();

//프록시 객체를 가져옴
Member findMember = em.getReference(Member.class, member.getId());
System.out.println("findMember = " + findMember.getClass());
// 값이 실제 사용되는 시점에 쿼리가 나간다.
// 찾을 때, ID값을 알고 있으니 조회하지 않음
System.out.println("findMember.getId() = " + findMember.getId());

// Name의 값은 알 수 없으므로 영속성 컨텍스트에 실제 객체를 요청
System.out.println("findMember.getName() = " + findMember.getName());
System.out.println("findMember.getName() = " + findMember.getName());
System.out.println("findMember = " + findMember.getClass());
/*
// 하이버네이트가 강제로 만든 프록시 클래스 
findMember = class jpabook.study.domain.Member$HibernateProxy$3UMPnBJl
*/

</aside>

<aside> ❗

프록시 특징

image.png

image.png



// member에 프록시 객체를 저장함 
Member member = em.getReference(Member.class, "id1");

member.getName();

image.png

  1. getName() 호출 Member target이 없음
  2. JPA가 영속성 컨텍스트에 요청 ( 진짜 Member 객체를 가져오도록 )
  3. 영속성 컨텍스트는 DB를 조회해서 진짜 Member 엔티티를 생성
  4. target이 진짜 엔티티를 참조하도록 함
  5. target.getName() 수행

<aside> ❗

프록시의 특징

Member m1 = em.find(Member.class, member1.getId());
Member m2 = em.getReference(Member.class, member2.getId());

// 절대 타입 비교를 == 을 사용해서는 안 된다.
System.out.println(m1.getClass() == m2.getClass()); // false
Member m1 = em.find(Member.class, member1.getId());
Member m2 = em.getReference(Member.class, member2.getId());

// 영속성 캐시에서 가져오기 때문에 프록시가 m2에 저장됨 
m2 = em.find(Member.class, member2.getId());
System.out.println(m2.getClass().getName());
System.out.println(m1.getClass() == m2.getClass());

/*
jpabook.study.domain.Member$HibernateProxy$SWAvcM1M
false
*/
Member member = em.getReference(Member.class, member.getId());

// member는 비영속 상태가 됨 -> 영속성 컨텍스트 도움을 받지 못함 
em.detach(member);

member.getName()
/*	
	org.hibernate.LazyInitializationException 예외를 터트림
	could not initialize proxy 오류 발생
	no Session
*/

</aside>

<aside> ❗

프록시 확인

emf.getPersistenceUnitUtil().isLoaded(member);
// false -> 초기화 X 
// true -> 초기화 O
Hibernate.initialize(entity)

[참고]

<aside> ❗

즉시 로딩, 지연 로딩

image.png

지연 로딩 Lazy을 사용해서 프록시로 조회

@Entity
public class Member {
	
	@Id
	@GeneratedValue
	private Long id;
	
	@Column(name = "USERNAME")
	private String name;
	
	@ManyToOne(fetch = FetchType.LAZY) 
	@JoinColumn(name = "TEAM_ID")
	private Team team; // team을 프록시 타입으로 조회함, 즉 Member만 DB에서 조회 
}

</aside>

<aside> ❗

지연 로딩

image.png

지연 로딩 LAZY을 사용해서 프록시로 조회

image.png

Team team = member.getTeam();
team.getName(); // 실제 team을 사용하는 시점에 초기화(DB 조회)

</aside>

<aside> ❗

Member와 Team을 자주 함께 사용한다면 ??

즉시 로딩 EAGER를 사용해서 함께 조회

@Entity
public class Member {
	
	@Id
	@GeneratedValue
	private Long id;
	
	@Column(name = "USERNAME")
	private String name;
	
	@ManyToOne(fetch = FetchType.EAGER) 
	@JoinColumn(name = "TEAM_ID")
	private Team team;
}

</aside>

<aside> ❗

즉시 로딩

image.png

즉시 로딩(EAGER), Member 조회시 항상 Team도 조회

image.png

<aside> ❗

</aside>