![[JPA] 08. 프록시와 연관관계 관리](https://inblog.ai/_next/image?url=https%3A%2F%2Finblog.ai%2Fapi%2Fog%3Ftitle%3D%255BJPA%255D%252008.%2520%25ED%2594%2584%25EB%25A1%259D%25EC%258B%259C%25EC%2599%2580%2520%25EC%2597%25B0%25EA%25B4%2580%25EA%25B4%2580%25EA%25B3%2584%2520%25EA%25B4%2580%25EB%25A6%25AC%26logoUrl%3Dhttps%253A%252F%252Finblog.ai%252Finblog_logo.png%26blogTitle%3D%25EB%25B0%25B1%25EC%2597%2594%25EB%2593%259C%25EB%25B8%2594%25EB%25A1%259C%25EA%25B7%25B8-dohyeong&w=1920&q=75)
프록시
프록시 기초
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](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fd15dfa4d-5bd9-4abf-b56a-bb7a2a8aaa2a%252FUntitled.png%3Ftable%3Dblock%26id%3D2462c68f-0656-4882-a075-bdb4ee6c0b57%26cache%3Dv2&w=3840&q=75)
- 프록시로 가져왔다가 실제 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