출처 : 자바 ORM 표준 JPA 프로그래밍 - 기본편
섹션 8. 프록시와 연관관계 관리
1. 프록시
1 - 1. 프록시 기초
- em.find() vs em.getReference()
- em.find(): 데이터베이스를 통해서 실제 엔티티 객체 조회
- em.getReference(): 데이터베이스 조회를 미루는 가짜(프록시) 엔티티 객체 조회
(실제 값이 사용되는 시점에 DB 쿼리를 함)
1 - 2. 프록시 특징
- 실제 클래스를 상속 받아서 만들어짐
- 실제 클래스와 겉 모양이 같다.
- 사용하는 입장에서는 진짜 객체인지 프록시 객체인지 구분하지 않고 사용하면 됨(이론상)
- 프록시 객체는 실제 객체의 참조(target)를 보관
- 프록시 객체를 호출하면 프록시 객체는 실제 객체의 메소드 호출
1 - 3. ⭐ 프록시의 특징 ⭐
- 프록시 객체는 처음 사용할 때 한 번만 초기화
- 프록시 객체를 초기화 할 때, 프록시 객체가 실제 엔티티로 바뀌는 것은 아님,
초기화되면 프록시 객체를 통해서 실제 엔티티에 접근 가능 - 프록시 객체는 원본 엔티티를 상속받음, 따라서 타입 체크시 주의해야함
(== 비교 실패, 대신 instance of 사용) - 영속성 컨텍스트에 찾는 엔티티가 이미 있으면 em.getReference()를 호출해도 실제 엔티티 반환
- 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화하면 문제 발생
(하이버네이트는 org.hibernate.LazyInitializationException 예외를 터트림)
2. 즉시 로딩과 지연 로딩
• 지연 로딩 LAZY을 사용해서 프록시로 조회
• 즉시 로딩 EAGER를 사용해서 함께 조회 (프록시 필요 X)
2 - 1. 🚨 프록시와 즉시로딩 주의 🚨
- 가급적 지연 로딩만 사용 (특히 실무에서)
- 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생
- 즉시 로딩은 JPQL에서 N+1 문제를 일으킴
(최초 쿼리 : 1, 그거 때문에 추가 쿼리(N)가 나감) - @ManyToOne, @OneToOne(X to One)은 기본이 즉시 로딩
→ LAZY로 설정 - @OneToMany, @ManyToMany는 기본이 지연 로딩
3. 지연 로딩 활용
3 - 1. 지연 로딩 활용 - 실무
- 모든 연관관계에 지연 로딩을 사용해라!
- 실무에서 즉시 로딩을 사용하지 마라!
- JPQL fetch 조인이나, 엔티티 그래프 기능을 사용해라!
(뒤에서 설명) - 즉시 로딩은 상상하지 못한 쿼리가 나감
4. 영속성 전이: CASCADE
특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들도 싶을 때
(연관 관계 매핑 X)
예) 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장
4 - 1. 🚨 영속성 전이: CASCADE - 주의!
- 영속성 전이는 연관관계를 매핑하는 것과 아무 관련이 없음
- 엔티티를 영속화할 때 연관된 엔티티도 함께 영속화하는 편리함을 제공할 뿐
4 - 2. CASCADE의 종류
- ALL: 모두 적용
- PERSIST: 영속
- REMOVE: 삭제
- MERGE: 병합
- REFRESH: REFRESH
- DETACH: DETACH
5. 고아 객체
- 고아 객체 제거: 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제
- orphanRemoval = true*
5 - 1. 🚨 고아 객체 - 주의
- 참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 보고 삭제하는 기능
- 참조하는 곳이 하나일 때 사용해야함!
- 특정 엔티티가 개인 소유할 때 사용
- @OneToOne, @OneToMany만 가능
- 참고: 개념적으로 부모를 제거하면 자식은 고아가 됨.
따라서 고아 객체 제거 기능을 활성화 하면,
부모를 제거할 때 자식도 함께 제거됨.
이것은 CascadeType.REMOVE처럼 동작함.
6. 영속성 전이 + 고아 객체, 생명주기
섹션 9. 값 타입
1. 기본값 타입
1 - 1. JPA의 데이터 타입 분류
- 엔티티 타입
• @Entity로 정의하는 객체
• 데이터가 변해도 식별자로 지속해서 추적 가능
• 예) 회원 엔티티의 키나 나이 값을 변경해도 식별자로 인식 가능 - 값 타입
• int, Integer, String처럼 단순히 값으로 사용하는 자바 기본 타입이나 객체
• 식별자가 없고 값만 있으므로 변경시 추적 불가
• 예) 숫자 100을 200으로 변경하면 완전히 다른 값으로 대체
2. 값 타입 분류
- 기본값 타입
• 자바 기본 타입(int, double)
• 래퍼 클래스(Integer, Long)
• String - 임베디드 타입(embedded type, 복합 값 타입)
- 컬렉션 값 타입(collection value type)
3. 임베디드 타입 (복합 값 타입)
- 새로운 값 타입을 직접 정의할 수 있음
- JPA는 임베디드 타입(embedded type)이라 함
- 주로 기본 값 타입을 모아서 만들어서 복합 값 타입이라고도 함
- int, String과 같은 값 타입
- 재사용
- 높은 응집도
3 - 1. 임베디드 타입과 테이블 매핑
테이블 설계와 객체 설계는 따로 할 수 있음.
- 임베디드 타입은 엔티티의 값일 뿐
- 임베디드 타입을 사용하기 전과 후에 매핑하는 테이블은 같음
- 객체와 테이블을 아주 세밀하게(find-grained) 매핑하는 것이 가능
- 잘 설계한 ORM 애플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많음
예시
3 - 2. 값 타입과 불변 객체
4. 값 타입 컬렉션
- 값 타입을 하나 이상 저장할 때 사용
- @ElementCollection, @CollectionTable 사용
- 데이터베이스는 컬렉션을 같은 테이블에 저장할 수 없다.
- 컬렉션을 저장하기 위한 별도의 테이블이 필요함
4 - 1. 🚨 값 타입 컬렉션의 제약사항
- 값 타입 컬렉션에 변경 사항이 발생하면,
주인 엔티티와 연관된 모든 데이터를 삭제하고,
값 타입 컬렉션에 있는 현재 값을 모두 다시 저장한다.
4 - 2. 정리
📌 식별자가 필요하고, 지속해서 값을 추적, 변경해야 한다면
그것은 값 타입이 아닌 엔티티
'Spring > JPA' 카테고리의 다른 글
JPA 강의 8 - 객체지향 쿼리 언어 2, JPA N + 1 문제 (중급 문법) (0) | 2022.12.19 |
---|---|
JPA 강의 7 - 객체지향 쿼리 언어 1 (기본 문법) (0) | 2022.12.19 |
JPA 강의 5 - 고급 매핑 (0) | 2022.12.19 |
JPA 강의 4 - 다양한 연관관계 매핑 (0) | 2022.12.19 |
JPA 강의 3 - 연관관계 매핑 기초 (0) | 2022.12.19 |