모르지 않다는 것은 아는것과 다르다.

Spring Jpa

프록시와 연관관계 관리

채마스 2022. 2. 27. 01:03

프록시

  • 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