프록시
- em.find() vs em.getReference()
- em.find(): 데이터베이스를 통해서 실제 엔티티 객체 조회 -> 바로 쿼리문을 날린다.
- em.getReference(): 데이터베이스 조회를 미루는
가짜(프록시)
엔티티 객체 조회 -> 실제로 사용될때 쿼리문을 날린다. - 프록시의 구조
- 실제 클래스를 상속 받아서 만들어진다.
- 실제 클래스와 겉 모양이 같다.
- 사용하는 입장에서 진짜 객체인지 프록시 객체인지 구분하지 않고 사용하면 된다.
- 프록시 객체의 초기화
- client 가 getName()을 호출하면 MemberProxy 는 영속성 컨텍스트에 Member 객체를 요청한다.
- 영속성 컨텍스트는 DB를 조회해서 실제 엔티티 객체를 생성한다.
- 그리고 Member target에 생성된 엔티티 객체를 연결한다.
- 이렇게 되면 target에 엔티티가 초기화 되므로 이후에 다시 조회할땐 바로 가져다 쓸수있다.
프록시의 특징
- 프록시 객체는 처음 사용할 때 한번만 초기화한다.
- 프록시 객체를 초기화 할 때, 프록시 객체가 실제 엔티티로 바뀌는 것이 아니다. -> 초기화되면 프록시 객체를 통해서 실제 엔티티에 접근이 가능할 뿐이다.
- 프록시 객체는 원본 엔티티를 상속받는다. 따라서 타입 체크 시 주의해야한다. ->
== 비교 실패, 대신 instance of 를 사용해야한다.
- 영속성 컨텍스트에 찾는 엔티티가 이미 있으면 em.getReference() 를 호출해도 실제 엔티티를 반환한다.
Member member1 = new Member();
member1.setUsername("member1");
em.persist(member1);
em.flush();
em.clear();
Member refMember = em.getReference(Member.class, member1.getId());
em.detach(refMember) // 여기서 준영속 상태가 되었다. em.close, em.clear 해도 마찬가지다
refMemver.getUsername() // 이 순간 에러 발생
- 위의 상황처럼
준영속 상태 일때 프록시를 초기화 하면 org.hibernate.LazyInitializationException 가 발생하고 실제로 실무에서 가장 많이 만나는 문제일 것이다.
프록시 확인
- 프록시 인스턴스의 초기화 여부 확인 : emf.getPersistenceUnitUtil.isLoaded(Object entity)
- 프록시 클래스 확인 방법 : entity.getClass()
- 프록시 강제 초기화 : org.hibernate.Hibernate.initialize(entity)
REFERENCES
- 김영한님의 자바 ORM 표준 JPA 프로그래밍 - 기본편
'Spring Jpa' 카테고리의 다른 글
JPA 관련 애노테이션 정리 (0) | 2022.03.24 |
---|---|
JPA DB 수동설정 (0) | 2022.03.24 |
JPA Id 생성전략 설정하기 (0) | 2022.02.27 |
영속성 컨텍스트 (0) | 2022.02.27 |
조회 성능 최적화 (0) | 2022.02.27 |