※ 본문은 김영한 선생님의 인프런 '자바 ORM 표준 JPA 프로그래밍 - 기본편' 강의를 듣고 정리한 내용임을 알립니다.
▶ Proxy
Q. Member와 Team의 연관관계가 있을 때, Member만 조회하고 싶은데 굳이 Team도 같이 불러와야만 하는가?
- em.find() : 데이터베이스를 통해 실제 Entity 객체 조회
- em.getReference() : 데이터베이스 조회를 미루는 가짜(Proxy) Entity 객체 조회
→ Proxy 특징
- 실제 클래스를 상속받았으므로 실제 클래스와 겉모양이 같음
- 사용하는 입장에서는 실제 객체와 Proxy 객체를 구분하지 않고 사용해도 됨
- Proxy 객체는 실제 객체의 참조(target)를 보관
- Proxy 객체를 호출하면 Proxy 객체는 실제 객체의 메소드 호출
★ Proxy 객체는 처음 사용할 때 한번만 초기화
★ Proxy 객체를 초기화할 때, Proxy 객체가 실제 Entity로 바뀌는 것은 아님
→ 초기화 이후 Poxy 객체를 통해서 실제 Entity 접근
★ Proxy 객체는 원본 Entity를 상속받음
→ 타입 체크 시 주의해야 함 (==비교 대신에 instance of 사용)
※ JPA는 같은 대상을 조회할 경우 ==비교에 true 값을 보장함
★ 영속성 컨텍스트에 찾는 Entity가 이미 있으면 em.getReference()가 em.find() 기능을 수행
→ 반대로 em.getReference()를 먼저 하고 em.find()를 하면 Proxy 객체만 두 번 조회하게 됨
★ 준영속 상태일 때 Proxy를 초기화하면 문제 발생
→ org.hibernate.LazyInitializationException 예외 발생
※ Proxy 관련 메소드
- emf.getPersistanceUnitUtil.isLoaded(Object entity) - Proxy 인스턴스의 초기화 여부 확인
- entity.getClass().getName() - Proxy 클래스 확인 방법
- Hibernate.initialize(entity); - Proxy 강제 초기화
▶ 즉시 로딩과 지연 로딩
→ 지연 로딩을 걸어둔 객체는 Proxy 객체로 조회
→ 지연 로딩을 걸어둔 객체를 사용하는 시점에 초기화 (DB 조회)
→ Member와 Team을 같이 사용할 일이 많은 경우 즉시 로딩 설정
★ 즉시 로딩 주의사항
- 실무에서는 가급적이면 지연 로딩 사용 권장
- 즉시 로딩은 예상치 못한 SQL이 발생할 수 있음
- 즉시 로딩은 JPQL에서 N+1 문제를 일으킴
- @ManyToOne, @OneToOne은 기본이 즉시 로딩 (LAZY로 설정해야 함)
- @OneToMany, @ManyToMany는 기본이 지연 로딩
=> XToOne에는 다 지연 로딩을 바른다고 생각하자!
=> JPQL fetch join이나 Entity 그래프 기능을 사용하자
▶ 영속성 전이(CASCADE)와 고아 객체
1. 영속성 전이(CASCADE) : 특정 Entity를 영속 상태로 만들 때 연관 Entity도 함께 영속 상태로 만드는 기능
→ parent에서 persist할 때 연관되어 있는 child를 같이 persist해줌
★ CASCADE는 연관관계 매핑과 아무 관련이 없음
→ Entity를 영속화할 때 연관된 Entity도 함께 영속화하는 편리함을 제공할 뿐
※ CASADE의 종류
→ ALL / PERSIST / REMOVE / MERGE / REFRESH / DETACH
=> 게시판에서 자주 사용 (게시글의 child는 해당 게시글만의 child이므로)
=> 소유자가 하나일 경우에 사용해주는 것이 좋다.
2. 고아 객체 제거 : 부모 Entity와 연관관계가 끊어진 자식 Entity 자동 삭제
→ orphanRemoval = true
→ Parent parent1 = em.find(Parent.class, id);
parent1.getChildren().remove(0);
→ 참조가 제거된 Entity는 다른 곳에서 참조하지 않는 고아 객체로 간주하고 삭제하는 기능
★ 고아 객체 주의사항
- 참조하는 곳이 하나일 때 사용
- 특정 Entity가 개인 소유일 경우 사용
- @OneToOne, @OneToMany만 가능
※ 부모를 제거하면 자식은 고아가 됨
→ orphanRemoval을 사용하면 부모를 제거할 때 자식도 함께 제거됨 (CascadeType.REMOVE처럼 동작)
※ CascadeType.ALL + orphanRemoval = true
→ 두 옵션을 함께 사용하면 부모 Entity를 통해서 자식의 생명주기를 관리할 수 있음
→ 도메인 주도 설계(DDD)의 Aggregate Root 개념을 구현할 때 유용
'JVM > JPA' 카테고리의 다른 글
객체지향 쿼리 언어 (JPQL) (0) | 2021.04.18 |
---|---|
값 타입 (0) | 2021.04.16 |
Entity Mapping (0) | 2021.04.15 |
영속성 관리 (0) | 2021.04.11 |
JPA란? (0) | 2021.04.10 |