- Proxy
- em.getReference() : 데이터베이스 조회를 미루는 가짜(프록시) 엔티티 객체 조회한다.
- em.find() : 데이터베이스를 통해서 실제 엔티티 객체를 조회한다.

getReference를 호출하는 시점에는 쿼리가 나가지않고, 이 값이 실제로 사용되는 시점에 쿼리가 나가게 된다.
위의 코드를 해석해 보자면 em.getReFerence로 Member클래스를 상속받고 있는 프록시 객체를 생성하게 되고, 이 생성된 프록시객체는 findMember.getUsername()처럼 실제로 사용하는 요청이들어올때 영속성 콘텍스트로부터 초기화 요청을 보내게 된다. 영속성컨텍스트는 실제 Member엔티티를 생성하게 되고 프록시는 타깃으로 엔티티를 참조하게 된다.

하이버네이트가 강제로 만든 가짜 클래스(프록시 클래스)
- 프록시 특징 1
- 실제 클래스를 상속받아서 만들어진다.
- 실제 클래스와 겉모양이 같다.
- 사용하는 입장에서는 진짜 객체인지 프록시 객체인지 구분하지 않고 사용하면 됨!(이론상)
- 하이버 네이트가 내부적으로 여러 프록시 라이브러리를 사용해서 만들어내게 된다.
- 프록시 특징 2
- 프록시 객체는 처음 사용할 때 한 번만 초기화
- 프록시 객체를 초기화할 때, 프록시 객체가 실제 엔티티로 바뀌는 것은 아니고 초기화가 되면 프록시 객체를 통해서 실제 엔티티에 접근 가능
- 프록시 객체는 원본 엔티티를 상속받는다. 따라서 타입 체크 시 주의해야 함 (==비교 실패, 대신 instance of 사용)
- 영속성 콘텍스트에 찾는 엔티티가 이미 있으면 em.getReference()를 호출해도 실제 엔티티 반환
- 즉시 로딩(LAZY)

@ManyToOne(fetch = FetchType.LAZY) 이런 식으로 LAZY옵션을 주게 되면 프록시로 Team엔티티를 조회하게 된다.


em.find로 실제 Member의 엔티티에서 TEAM의 클래스를 조회하였는데 위와 같이 Member에서 참조하는 Team은 프록시로 조회가 된 모습을 볼 수 있다.
여기서 아래와 같이 코드를 추가해 보았다.
System.out.println("=============");
m.getTeam().getName();
System.out.println("==============");
System.out.println("m.getTeam().getClass() = " + m.getTeam().getClass());

위에서 getTeam.getClass로 실제 값을 사용하지 않았을 경우에는 쿼리가 나가지 않고 프록시로 생성된 엔티티를 반환받았다.
그런데 실제로 값을 사용하는 getTeam.getName을 호출하는 시점에 위와 같이 SELECT쿼리나 나가게 되고 이때 프록시객체는 영속성컨텍스트로부터 초기화를 요청하고 Team의 엔티티를 생성해서 프록시엔객체가 Team엔티티를 참조하게 된다. 그래서 위와 같이 조회가 끝난 뒤 Team의 클래스를 조회하여도 프록시엔티티의 주소가 나오게 된다.
정리를 하자면 FetchType.LAZY로 지연 로딩(LAZY)을 사용해서 프록시로 연관된 객체를 가져온다.
- 즉시 로딩(EAGER)


위와 같이 FechType을 EAGER로 설정을 하게 되면 즉시 로딩으로 Member를 조회할 때 한방 쿼리로 Team도 함께 Join을해서 가져오게 된다.

그리고 이 Member엔티티의 Team의 클래스를 조회한 결과 LAZY의 프록시객체가 아닌 실제 Team의 엔티티가 반환된 걸 볼 수 있다.
- 프록시와 즉시 로딩 주의
- 가급적 지연 로딩만 사용할 것(특히 실무에서)
- 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생
- 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.
- @ManyToOne, @OntoOne은 디폴드 값이 즉시로딩이다. 따라서 LAZY로 설정
- @OneToMany, @ManyToMany는 디폴드값이 지연 로딩이다.
- 영속성 전이 : CASCADE
특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶을 때
ex) 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장

위의 코드와 같이 cascade = CascadeType.ALL 설정을 해주면 이 엔티티를 저장할 때 이와 연관된 엔티티도 함께 영속 상태로 만들게 된다.


영속성 콘텍스트에 다 저장하려면 em.persist를 3번 호출해야 하는데 위의 코드를 보면 em.persist로 parent객체 하나만 저장해주었다.
하지만 영속성 전이로 연관된 객체들까지 같이 영속성컨텍스트에 저장되게 된다.
- 주의사항!
- 영속성 전이는 연관관계를 매핑하는 것과 아무 관련이 없음
- 엔티티를 영속화할 때 연관된 엔티티도 함께 영속화하는 편리함을 제공할 뿐이다.
- 주로 라이플 사이클이 같을 때 사용하고 소유 엔티티가 하나일 때 사용한다. (다른 엔티티와 관계가 있을 경우 사용 x)
- 고아 객체
고아 객체 제거 : 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제한다.
orphanRemoval = true

위와 같이 orphanRemoval = true를 설정해주면 된다.



위의 코드처럼getChildList(orphanRemoval)에서 연관관계가 끊어지면 자동으로 삭제가 된다. 여기서 중요한 점은 원래 엔티티 연관관계에서는 연관관계 주인만 수정, 삭제 등을 할 수 있으나 Cascade와 orphanRemoval는 연관관계와는 상관없이 영속 컨텍스트에 있는 엔티티의 생명주기를 관리한다.
- 주의사항!
- 참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 보고 삭제하는 기능이다.
- 참조하는 곳이 하나일 때 사용해야 한다.
- 특정 엔티티가 개인 소유할 때 사용
-@OneToOne, @OneToMany만 가능
출처 : https://www.inflearn.com/course/ORM-JPA-Basic#
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의
JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., 본 강의는 자바 백엔
www.inflearn.com

'JPA' 카테고리의 다른 글
객체지향 쿼리 언어 (0) | 2021.10.13 |
---|---|
값 타입 (0) | 2021.10.12 |
고급 매핑 (0) | 2021.10.10 |
다양한 연관관계 매핑 (0) | 2021.10.09 |
연관관계 매핑 (0) | 2021.10.08 |