em.find() : DB를 통해서 실제 엔티티 객체 조회
em.getReference() : DB 조회를 미루는 가짜(프록시) 엔티티 객체 조회 (쿼리가 안나가는데 객체가 조회됨) getReference()를 할때는 쿼리가 나가지 않지만 나중에 진짜 쓰이는 곳이 나올 때 쿼리가 나간다.
실제 엔티티를 상속받아서 만들어졌기 때문에 실제 클래스와 겉모양이 같지만, 프록시 객체는 실제 객체의 참조를 보관한다.
이론상 사용하는 입장에서는 진짜인지 프록시인지 구분하지않고 그냥 사용하면 된다.
프록시 객체는 실제 객체의 참조를 보관하기 때문에 프록시 객체를 호출하면 프록시 객체는 실제 객체의 메소드를 호출한다.
프록시 객체의 초기화
Member member = em.getReference(Member.class, "id1");
member.getName();
Member member1 = new Member();
member1.setName("member1");
em.persist(member1);
em.flush();
em.clear();
Member refMember = em.getReference(Member.class, member1.getId());
System.out.println("refMember = " + refMember.getClass()); //Proxy
Member findMember = em.find(Member.class, member1.getId());
System.out.println("findMember = " + findMember.getClass());
System.out.println("(refMember == findMember) = " + (refMember == findMember));
위의 경우에는 ==을 보장해야하기 때문에 두개 다 프록시가 반환된다.
이유는 다음과 같다.
이미 영속성 컨텍스트에 있는 것이므로 프록시로 가져와 봐야 아무 이점이 없다.
JPA에서는 한 트랜잭션 안에서 동일성을 보장하는데, 그 때문에 트랜잭션 안에서 가져온 객체들의 == 연산을 항상 true로 보장해준다. 이 때문에 프록시를 2개 호출하여도 같은 프록시를 쓴다.
프록시 인스턴스의 초기화 여부 확인
PersistenceUnitUtil.isLoaded(Object entity)
emf.getPersistenceUnitUtil.isLoaded(Object entity)
프록시 클래스 확인 방법
entity.getClass()출력
프록시 강제 초기화
org.hibernate.Hibernate.initialize(entity)
Hibernate.initialize(entity);
JPA 표준은 강제 초기화 없음