Life Developer
인생 개발자
[JPA]프록시객체 - getReference (와 find 차이)

 

프록시는 이렇게 만든다.

 

.getReference(~~~)

 

실제 사용 예는 밑에서..

 

 

 

 

 

 

 

아래 설명도 써놨지만 Member findMember = em.getReference(Member.class, member.getId());

이런 식으로 사용한다.

 

곧 findMember는 프록시이다.


Member findMember = em.find(Member.class, member.getId()); 와는 달리

Member findMember = em.getReference(Member.class, member.getId()); 를 딱 실행하면

 

select 쿼리가 db로 안날라간다.

 

즉, findMember는 진짜 엔티티가 아니라 가짜 엔티티이며, 실제 객체의 참조를 보관한다.

Member findMember = em.getReference(Member.class, member.getId()); 를 실행하면

프록시 객체를 가져온다. (가짜 엔티티, 엔티티가 아님)

그 객체에는 get요청한 Id 정보만 있다.

그래서 System.out.println(findMember.getId()); 를 하면 Id가 출력이 된다.

db에 갈 필요가 없다는것이다.

 

근데 딱 findMember.getUserName() 을 하는순간 가짜 엔티티(프록시객체)에는 name이 없기 때문에

DB를 통해 name 값을 가져온다. 이것을 프록시 객체의 초기화라고 한다.

 

프록시의 초기화는 딱 한번만 이루어진다.

 

 

 

 

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

em.persist(member);

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

// Member findMember = em.find(Member.class, member.getId());
Member findMember = em.getReference(Member.class, member.getId());
System.out.println(findMember.getClass()); //class hellojpa.Member$HibernateProxy$7XonaGYN 가짜클래스임(proxy가만듦)
System.out.println(findMember.getId());//이미 위에서 id로 찾았기 때문에 db에서 안가져옴
System.out.println(findMember.getUserName()); //모르는 정보니까 이때 db에 쿼리를 날려서 team이랑 조인함

System.out.println(" =============== ");
tx.commit(); //이시점에 DB 쿼리가 날라감

 

 

 

 

======================================================================

 

그리고 주의 할점도 있다.

 

아래처럼 진짜 member entity를 영속성 컨텍스트에 등록하고 clear 없이 getReference를 하면 영속성 컨텍스트에

등록되어 있는 member를 가지고 온다.

그래서 이전것을 재활용한다.

 

하지만 clear()를 호출해 영속성 컨텍스트를 비우고 getReference를 하면 프록시객체를 불러오게 되므로

서로 같은 객체가 아니게 된다.

 

getReference를 했는데 프록시 객체가 아닌 상태가 되는것이다.......ㅎ후

 

Member m1= em.find(Member.class,member1.getId());
System.out.println("m1.getClass() = " + m1.getClass());
em.clear();
Member m2= em.getReference(Member.class,member1.getId());
System.out.println("m2.getClass() = " + m2.getClass());

System.out.println(" =============== ");
tx.commit(); //이시점에 DB 쿼리가 날라감

 

 

여기서 더 심화해보자.

 

Member m1= em.getReference(Member.class,member1.getId());
System.out.println("m1.getClass() = " + m1.getClass());

Member m2= em.find(Member.class,member1.getId());
System.out.println("m2.getClass() = " + m2.getClass());
System.out.println("m1==m2"+(m1.getClass() == m2.getClass()));

System.out.println(" =============== ");

 

그렇다면 이건 어떻게 나올까?

1. 내가 예상한것은 영속성 컨텍스트에 프록시 객체가 담길것이고,

2. find 해서 가져오려 했으나 영속성 컨텍스트에 Member객체가 있기에 db로 안가고

    프록시 객체를 그냥 가져와서 true가 나온다...

 

가 예상이었다.

 

근데 결과는 2번이 약간 달랐다.

일단 db로 쿼리는 select 때린다.

근데 가져온것은 프록시 객체.  ㅡㅡ.... 아니 DB왜 간거지.

 

그냥 DB까지 갔으나 영속성 컨텍스트에 있는것을 가져다 쓴다...기억하자

 

 

 

=============================================================

 

프록시 초기화가 되었는지 확인 하는법도 있다.

EntityManageFactory 객체 .getPersistenceUnitUtil().isLoaded(프록시객체) 를 하면 boolean 값으로 나오게 된다.!

 

Member m1 = em.getReference(Member.class, member1.getId());
System.out.println("m1.getClass() = " + m1.getClass());

m1.getId();
System.out.println("초기화 되었냐?" + emf.getPersistenceUnitUtil().isLoaded(m1));
m1.getUserName();
System.out.println("초기화 되었냐?" + emf.getPersistenceUnitUtil().isLoaded(m1));

System.out.println(" =============== ");
tx.commit(); //이시점에 DB 쿼리가 날라감

 

 

 

여기까지 이해했으면 프록시 정복한거임 푸헤ㅔㅎ

 

 

  Comments,     Trackbacks