inblog logo
|
백엔드블로그-dohyeong
    JPA

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

    Aug 30, 2023
    [JPA] 08. 프록시와 연관관계 관리
    Contents
    프록시프록시 기초지연 로딩 활용즉시 로딩영속성 전이 CASCADE고아 객체영속성 전이 + 고아 객체 , 생명주기

    프록시

    프록시 기초

    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

    RSS·Powered by Inblog