프록시와 연관관계 관리
프록시
프록시를 사용하는 이유는?
엔티티를 조회할 때 연관된 엔티티가 항상 사용되는 것은 아니다.
EX) Member의 name만 알고 싶은데 Member 엔티티와 연관된 Team 엔티티를 가져올 필요가 없음
JPA는 엔티티가 실제 사용될 때까지 DB 조회를 지연하는 방법을 제공한다. (지연로딩)
프록시 기초
EntityManager.getReference()를 호출하면, JPA는 DB를 조회하지 않고 실제 엔티티 객체를 생성하지 않는다.
대신, DB 접근을 위임한 프록시 객체를 반환한다.
프록시 객체는 실제 객체에 대한 참조를 보관하고, 프록시 객체의 메소드를 호출 했을 때 실제 객체의 메소드를 호출한다.
프록시 특징
- 프록시 객체는 처음 사용할 때 한 번만 초기화된다.
- 프록시 객체를 초기화한다고 프록시 객체가 실제 엔티티로 바뀌는 것은 아니다.
- 프록시 객체 초기화 후 프록시 객체를 통해서 실제 엔티티에 접근하는 것이다.
- 프록시 객체는 원본 엔티티를 상속 받아 만들어지므로, 타입 체크 시 주의해서 사용해야 한다.
- 영속성 컨텍스트에 찾고자 하는 엔티티가 이미 있으면, DB를 조회할 필요가 없으므로 em.getReference()를 호출해도 프록시가 아닌 실제 엔티티를 반환한다.
- 프록시 초기화는 영속성 컨텍스트의 도움을 받아야 가능하므로, 준영속 상태의 프록시를 초기화하면 예외가 발생한다.
프록시 객체의 초기화
프록시 객체는 생성 후 실제 사용될 때 DB를 조회해서 실제 엔티티 객체를 생성하는데, 이를 프록시 객체의 초기화라고 한다.
- 프록시 객체에 getName()을 호출해서 데이터를 조회한다.
- 프록시 객체는 실제 엔티티가 생성되어 있지 않으면 영속성 컨텍스트에서 실제 엔티티 생성을 요청한다. (프록시 객체 초기화)
- 영속성 컨텐스트는 DB를 조회해서 실제 엔티티 객체를 생성한다.
- 프록시 객체는 생성된 실제 엔티티 객체의 참조를 Member target 멤버 변수에 보관한다.
- 프록시 객체는 실제 엔티티 객체의 getName()을 호출해서 결과를 반환한다.
프록시 확인
- PersistenceunitUtil.isLoaded(Object entity) 메소드를 사용하면 프록시 인스턴스의 초기화 여부를 알 수 있다.
- getClass() 메소드를 통해 현재 인스턴스가 프록시 객체인지 진짜 객체인지 확인할 수 있다.
- JPA 표준에는 프록시 강제 초기화 메소드가 없으나, 하이버네이트에서 initalize() 메소드를 통해 강제 초기화 메소드를 제공한다.
Member m1 = em.find(Member.class, member1.getId()); // 직접 조회
Member m2 = em.getReference(Member.class, member2.getId()); // 프록시 조회
if(m1.getClass() == m2.getClass()) // False
if(m2 instanceof Member) // True
지연로딩과 즉시로딩
- 지연 로딩: 연관된 엔티티를 프록시로 조회하며, 프록시를 실제 사용할 때 초기화하면서 데이터베이스를 조회한다.
- 즉시 로딩: 연관된 엔티티를 즉시 조회하며, 하이버네이트는 가능하면 SQL 조인을 사용해서 한 번에 조회한다.
영속성 전이
영속성 전이란
특정 엔티티를 영속 상태로 만들 때, 연관된 엔티티도 함께 상속 상태로 만드는 것
EX) 부모 엔티티 저장 시 자식 엔티티도 함께 저장
CASCADE의 종류
- ALL
- PERSIST
- MERGE
- REMOVE
- REFRESH
- DETACH
persist와 remove는 플러시를 호출해야 전이가 발생
자식 Entity를 소유하는 Entity가 부모 하나일때 CASCADE.ALL을 사용
고아 객체
부모 엔티티와 연관관계가 끊어진 자식 엔티티를 고아 객체라 한다.
orphanRemoval=true
해당 속성 사용 시, 연관 관계를 제거하거나, 부모 객체가 제거되는 경우 자식 객체가 제거된다.
참조하는 곳이 하나일 때 사용해야하며, 특정 Entity가 자식 Entity를 개인 소유할 때 사용
CascadeType.ALL과 orphanRemoval=true를 함께 사용한다면?
- 스스로 생명주기를 관리하는 Entity는 em.persist()로 영속화, em.remove()로 제거
- 상기 두 옵션을 모두 활성화하면 부모 Entity를 통해 자식 Entity의 생명주기를 관리할 수 있음
// 자식을 저장하려면 부모에 등록하면 됨
Parent parent = em.find(Parent.class, parentId);
parent.addChild(child1);
// 자식을 제거하려면 부모에서 제거하면 됨
parent.getChildren().remove(child1);
728x90
'# 강의 > [인프런] 자바 ORM 표준 JPA 프로그래밍' 카테고리의 다른 글
[完] 값 타입 (0) | 2022.05.09 |
---|---|
고급 매핑(상속, Mapped Superclass) (0) | 2022.02.20 |
엔티티 매핑 2 (연관관계) (0) | 2022.01.12 |
엔티티 매핑 1(테이블, 컬럼, 키 매핑 전략) (0) | 2022.01.12 |
영속성 관리 - 내부 동작 방식 (0) | 2022.01.12 |
JPA는 왜 사용해야 하는가? (0) | 2022.01.06 |