EntityManager 클래스의 getReference() 메서드를 사용해서 프록시 엔티티를 조회 할 수 있다.
getReference()를 사용해서 객체를 얻게 되면, 데이터베이스에서 조회를 미룰 수 있다.
이때, HibernateJPA에서는 Proxy 객체를 반환해준다.
해당 프록시 객체는 실제 클래스를 상속해서 만들어 졌기 때문에, 겉 모양이 같으며, 사용자 입장에서는 구분하지 않고 사용할 수 있다.
프록시 객체는 실제 객체의 참조(target)를 보관하고, 프록시 객체를 호출하면 프록시 객체는 실제 객체의 메서드를 호출한다.
- 프록시 객체는 처음 사용할 때 한 번만 초기화 되며, 실제 엔티티로 바뀌는 것이 아니다.
(ex: 초기화시 MemberProxy&kfjsd13 -> Member 로 바뀐다는 것이 아님)- 따라서, 타입 체크 시 == 비교로 하게되면 false를 반환
- 영속성 컨테스트에 찾는 엔티티가 이미 있다면 em.getReference()를 호출해도 실제 엔티티를 반환한다.
- 영속성 컨테스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화하면 Exception 발생
- 하이버네이트의 경우 LazyInitializationException
// find()로 조회한 Entity와 getReference()로 조회한 Entity의 비교
private static void main(){
/*
영속성 컨테스트 초기화 상태
*/
Member m1 = em.find(Member.class, member1Id);
Member m2 = em.getReference(Member.class, member2Id);
boolean b1 = m1.getClass().getName() == m2.getClass().getName();
boolean b2 = m1 instanceof Mebmer;
boolean b3 = m2 instanceof Member;
// b1(==) : false
// b2(m1 instanceof Member) : true
// b3(m2 instanceof Member) : true (Proxy)
}
private static void main(){
/*
영속성 컨테스트 초기화 상태
*/
Long member1Id = 1;
Member m1 = em.getReference(Member.class, member1Id);
Member m2 = em.getReference(Member.class, member1Id);
//m1 == m2 => true
//같은 프록시 객체 반환
//m1.getClass() => class (패키지 경로).Member$HibernateProxy$ASD4QQQ
//m2.getClass() => class (패키지 경로).Member$HibernateProxy$ASD4QQQ
Member m3 = em.getReference(Member.class, member1Id);
Member m4 = em.find(Member.class, member1Id);
//m3 == m4 => true
//JPA에서는 한 번 프록시가 호출 되면 find()를 사용하더라도 프록시 객체 반환
//m3.getClass() => class (패키지 경로).Member$HibernateProxy$HDfa4QQQ
//m4.getClass() => class (패키지 경로).Member$HibernateProxy$HDfa4QQQ
}
3번 사항 관련 예시
private static void main(){
/*
영속성 컨테스트 초기화 상태
*/
Long member1Id = 1;
Member m1 = em.getReference(Member.class, member1Id);
//emem.detach(m1) 또는
em.close();
m1.getUsername();
// -> Exception 발생 프록시 초기화 불가
}
프록시 관련 메서드
- 프록시 인스턴스 초기화 여부 확인
- PersistenceUnitUtil.isLoaded(Object entity)
- emf.getPersistenceUnitUtil().isLoaded(entity)로 사용해야함
- 프록시 클래스 확인 방법
- entity.getClass().getName()
- 프록시 강제 초기화
- org.hibernate.Hibernate.initialize(entity);
- JPA 표준에는 강제 초기화가 없다 : getReference()로 얻은 객체의 getXXX() 강제 호출
출처 관련 : https://tan-sog.tistory.com/90
'DB > JPA' 카테고리의 다른 글
[JPA] 영속성 전이와 고아 객체 (0) | 2025.02.24 |
---|---|
[JPA] 즉시 로딩과 지연 로딩 (0) | 2025.02.22 |
[JPA] 상속관계 매핑 (0) | 2025.02.10 |
[JPA] 다양한 연관관계 매핑 (0) | 2025.02.09 |
[JPA] 변경 감지와 병합 / 준영속 엔티티 (0) | 2025.02.08 |