[JPA] 프록시
지연 로딩을 사용하기 위한 프록시 객체는 무엇인가?
※ 코드는 강의에서 사용된 것과 다릅니다.
<a href = https://github.com/jaewon-ju/Learning_Spring>jaewon-ju Github Address</a>
✏️ 프록시
프록시
: 엔티티의 지연 로딩을 관리하기 위해 사용하는 객체
- 엔티티 객체에 대한 참조를 가지고 있다.
- 프록시 객체의 메소드를 호출하면, 프로시 객체는 실제 엔티티의 메소드를 호출한다.
언제 프록시를 사용하는가? ➜ 테이블을 조회할 때, 연관관계 객체는 필요하지 않은 경우
연관되어 있는 객체를 함께 조회하려면, Join을 사용해서 테이블을 함께 조회해야 한다. ➜ 쿼리가 복잡해진다.
따라서, 비즈니스 로직에서 연관관계 객체가 필요하지 않다면 프록시를 사용한다.
■ 특징
- 실제 엔티티를 상속받아서 만들어진다.
- 실제 엔티티의 참조를 보관한다.
- 프록시는 처음 사용할 때 한 번만 초기화된다.
em.find()는 실제 엔티티를 조회하는 메소드이고,em.getReference를 사용하면 프록시를 조회할 수 있다.
⚠️ 영속성 컨텍스트에 엔티티가 이미 존재하면, em.getReference를 호출해도 실제 엔티티를 반환한다.
■ 초기화
프록시 초기화란?
: 프록시 객체가 처음으로 실제 엔티티의 데이터에 접근할 때 발생하는 과정
1
2
Issue issue1 = em.getReference("Issue.class","issue1");
issue1.getTitle();
-
em.getReference("Issue.class","issue1");를 호출하면, 프록시 객체인IssueProxy를 반환한다. -
issue1.getTitle();를 호출하면, 실제 엔티티를 호출해야 한다. 엔티티가 생성되지 않았다면, 영속성 컨텍스트에 초기화 요청을 한다. -
영속성 컨텍스트는 DB에서 Issue 엔티티를 조회한다.
-
IssueProxy객체는 참조를 통해Issue객체의getTitle()함수를 호출한다.
⚠️ 프록시 객체가 준영속 상태인 경우, 프록시를 초기화하면 오류가 발생한다!
✏️ 즉시 로딩과 지연 로딩
■ 즉시 로딩
엔티티를 조회할 때 해당 엔티티의 연관된 엔티티들도 함께 즉시 로드하는 전략
@JoinColumn(fetch = FetchType.EAGER)를 사용한다.@ManyToOne,@OneToOne은 기본 값이 즉시 로딩이다.
education_content 테이블은 menu_id 를 FK로 가지고 있다.
만약, @JoinColumn(fetch = FetchType.EAGER) 로 설정되어 있다면, education_content를 조회할 때 항상 menu도 함께 조회한다.
■ 지연 로딩
엔티티를 실제로 필요로 할 때까지 연관된 엔티티의 로딩을 지연시키는 전략
@JoinColumn(fetch = FetchType.LAZY)를 사용한다.@OneToMany,@ManyToMany는 기본 값이 지연 로딩이다.
education_content 테이블은 menu_id 를 FK로 가지고 있다.
만약, @JoinColumn(fetch = FetchType.LAZY) 로 설정되어 있다면, education_content를 조회할 때 menu는 프록시 객체로 조회된다!
- 실무에서는 가급적 지연 로딩을 사용해야 한다.
- 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.
✏️ CASCADE
영속성 전이 (CASCADE)
: 한 엔티티에 대한 변경이 연관된 다른 엔티티에 자동으로 반영되는 기술
- 특정 엔티티를 영속 상태로 만들 때, 연관된 엔티티도 함께 영속 상태로 만들 수 있다.
- 두 엔티티의 라이프 사이클이 동일할 때 사용하는 것이 좋다.
■ 종류
- CascadeType.ALL : 모든 작업(변경, 영속, 삭제 등)에 CASCADE 적용
- CascadeType.PERSIST : 부모 엔티티를 영속화할 때 연관된 자식 엔티티도 함께 영속화
- CascadeType.MERGE : 부모 엔티티가 병합될 때 연관된 자식 엔티티도 함께 병합
- CascadeType.REMOVE : 부모 엔티티가 삭제될 때 연관된 자식 엔티티도 함께 삭제
- CascadeType.DETACH : 부모 엔티티가 영속성 컨텍스트에서 분리될 때 연관된 자식 엔티티도 함께 분리
- CascadeType.REFRESH : 부모 엔티티를 새로고침할 때 연관된 자식 엔티티도 함께 새로고침
✏️ Orphan Removal
부모 엔티티와의 관계가 끊어진 자식 엔티티를 자동으로 삭제하는 기능
- 부모 엔티티테서 특정 자식 엔티티를 제거하는 것은, 참조를 삭제하는 것이다.
- Orphan Removal 기능을 사용하면, 부모가 없어진 고아 객체를 DB에서도 완전히 삭제한다.
Orphan Removal은 @OneToOne, @OneToMany 에서만 사용 가능하다.
■ CASCADE + Orphan Removal
CascadeType.ALL, orphanRemoval = true 속성을 함께 사용하면, 부모 엔티티를 통해서 자식의 생명 주기를 관리할 수 있다.
