[JPA] 08. 프록시와 연관관계 관리

Aug 30, 2023
[JPA] 08. 프록시와 연관관계 관리

프록시

프록시 기초

em.getReference(Member.class, member.getId()); System.out.println("findMember = " + findMember.getClass()); // 출력시 프록시 객체 //findMember = class hellojpa.Member$HibernateProxy$sxPV1plH
→ 데이터베이스 조회를 미루는 가짜(프록시) 엔티티

프록시 특징

  • 프록시 객체는 실제 객체의 참조를 보관
  • 호출하면 프록시 객체는 실체 객체의 메소드 호출
  • 프록시객체는 처음 사용할 때 한번만 초기화
  • 프록시 객체는 원본 엔티티를 상속받음(ProxyXX클래스) 따라서 타입 체크시 주의해함
    • 따라서 ==비교할 때는 instance of 로 사용
  • 영속성 컨텍스트에 있는 엔티티가 이미 있으면 getReference() 를 호출해도 실제 엔티티를 호출함 (반대도 마찬가지임 프로식를 호출하고 find하면 find를 해도 프록시를 반환)
  • 영속성 컨텍스트의 도움을 받을 수 없는 준영속성 상태일 때
 

프록시 인스턴스의 초기화 여부 확인

PersistenceUnitUtil.isLoaded(Object entity)

프록시 클래스 확인 방법

entity.getClass().getName()

프록시 강제 초기화

org.hibernate.Hibernate.initialize(entity);
 
 

지연 로딩 활용

 
지연 로딩 LAZY 을 사용해서 프록시로 조회
@ManyToOne(fetch = FetchType.LAZY)
notion image
  • 프록시로 가져왔다가 실제 team을 사용하는 시점에서 데이터베이스에서 조회함

즉시 로딩

Member와 Team을 자주 함께 사용하는 구조면?
즉시 로딩 EAGER 을 사용
@ManyToOne(fetch = FetchType.EAGER)
 

프록시와 즉시로딩 주의

  • 가급적 지연 로딩만 사용 ( 특히 실무에서 )
  • 즉시 로딩은 JPQL 에서 N+1 문제를 일으킴 ( team 마다 여러개가 나가야 해서 첫번째 쿼리 1 + 남은 쿼리 N)
List<Member> members = em.createQuery("select m from Member m", Member.class) .getResultList();
  • sql로 변역 -> SQL : select * from member
    • 즉시 로딩으로 되어있어서
    • Team 도 다 있어야 함
    • 그래서 select * from Team 쿼리도 나감
 
  • @ManyToOne, @OneToOne 은 기본이 즉시 로딩 → LAZY로 설정
  • @OneToMany , @ManyToMany는 기본이 지연로딩
 
지연 로딩 활용 → 실무
  • 모든 연관관계에 지연 로딩 사용
  • JPQL fetch 조인이나, 엔티티 그래프 기능을 사용
  • 즉시 로딩은 상상하지 못한 쿼리가 나간다

영속성 전이 CASCADE

💡
특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속성 상태로 만들고 싶을 때
 
@OneToMany(mappedBy = "parent" , cascade = CascadeType.ALL)
 
  • 소유자가 하나일때 cascade 괜찮음 ( 단일 엔티티의 종속적일 때 사용 - 라이프 사이클이 매우 유사하다는 의미 )
  • 하지만 여러개의 연관관계가 있을때는 사용하면 운영하기 넘 힘들어짐
 

고아 객체

💡
부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제
@OneToMany(mappedBy = "parent", orphanRemoval = true)
 

주의

  • 참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 보고 삭제하는 기능
  • 참조하는 곳이 하나일 때 사용해야함
  • 특정 엔티티가 개인 소유일 때 사용
  • OneToOne, OneToMany 만 가능
  • CasCadeType.REMOVE처럼 사용
 

영속성 전이 + 고아 객체 , 생명주기

CascadeType.ALL + orphanRemoval=true
  • 두 옵션을 모두 활성화 하면 부모 엔티티를 통해서 자식의 생명 주기 관리 가능 (child를 parent가 관리할 수 있음)
  • 도메인 주도 설계(DDD)의 Aggregate Root 개념을 구현할 때 유용
 
 

 
 
 
Share article

백엔드블로그-dohyeong