목차
09 연관관계 매핑
ㄴ9.1 연관관계 매핑 종류와 방향
ㄴ9.2 프로젝트 생성
ㄴ9.3 일대일 매핑
ㄴ9.3.1 일대일 단방향 매핑
ㄴ9.3.2 일대일 양방향 매핑
ㄴ9.4 다대일, 일대다 매핑
ㄴ9.4.1 다대일 단방향 매핑
ㄴ9.4.2 다대일 양방향 매핑
ㄴ9.4.3 일대다 단방향 매핑
ㄴ9.5 다대다 매핑
ㄴ9.5.1 다대다 단방향 매핑
ㄴ9.5.2 다대다 양방향 매핑
ㄴ9.6 영속성 전이
ㄴ9.6.1 영속성 전이 적용
ㄴ9.6.2 고아 객체
ㄴ9.7 정리
9.1 연관관계 매핑 종류와 방향
RDBMS를 사용할 때 설계가 복잡해지면 테이블 한개가 아니라 여러 테이블을 연관 관계를 설정하고 Join의 기능을 활용한다. JPA에서도 테이블의 연관 관계 -> 엔티티 간의 연관관계로 표현함.
그러나 객체와 테이블의 성질이 다르기 때문에 정확한 연관관계는 표현할 수 없으나 JPA에서 연관관계를 매핑하고 사용할 수 있다.
매핑 종류
- 일대일(1:1) : One To One
- 일대다(1:N) : One To Many
- 다대일(N:1) : Many To One
- 다대다(N:M) : Many To Many
매핑 방향
- 단방향 - 두 엔티티 관계에서 한쪽의 엔티티만 참조하는 형식
- 양방향 - 두 엔티티 관계에서 각 엔티티가 서로의 엔티티를 참조하는 방식
연관관계가 설정되면 다른 테이블의 PK값이 외래키로 갖게된다. 일반적으로 이렇게 외래키를 갖는 테이블이 그 관계의 주인(Owner)이 된다고 표현하며 주인은 외래키를 사용 할 수 있고, 상대 엔티티는 작업만 수행할 수 있다.
9.3 일대일 매핑
일대일 매핑은 예를 들어 상품 테이블(Product) -> 상품상세테이블(Product Detail) 처럼 하나의 테이블이 하나의 다른 테이블에만 매핑되는 구조는 일대일 관계이므로 일대일 매핑이다.
일대일 단방향 매핑
방법은 해당 이어줄 엔티티1(테이블) 필드에 @OneToOne, @JoinColumn(name = "구분할 이름")로 엔티티2를 넣는다.
이렇게 해당 필드를 갖고 있는 엔티티1이 주인(Owner)이다.
이 때 @OneToOne 어노테이션 인터페이스를 살펴보면 fetch가 EAGER로 기본값으로 설정되어있기 때문에 엔티티1을 조회할때 즉시 엔티티2를 조회하며, left outer join을 한다.
기본값으로 되어있으니 @OneToOne(fetch = LAGY)로 바꿀 수 있다.
여기서 optional 설정도 살펴보면 optional에 기본값이 true로 되어있는데 이것을 false로 바꾸면 연관관계인 엔티티2가 null인 값을 허용하지 않게되며(not null) 이때는 inner join을 한다.
일대일 양방향 매핑
양방향은 엔티티1의 필드에만 엔티티2를 OneToOne 어노테이션을 추가했는데 이번엔 엔티티2의 필드에도 엔티티1를 OneToOne 어노테이션을 붙여주면 된다.
그럼 엔티티1과 엔티티2는 각자 서로를 참조할 수 있다.
그러나 이때 left outer join을 두번이나 수행하므로 효율성이 떨어지고 주로 일대일 단방향 매핑을 쓴다.
그래도 양방향 매핑을 쓰면서 한 쪽 객체가 주인이 되도록 (외래키 소유) 하기 위해서는 mappedBy = "엔티티2"라고 쓰면 아까 단방향 매핑처럼 일대일 매핑처럼 외래키를 엔티티1이 갖게된다.
그러나 여기서 또 주의해야할 점은 양방향 설정을 꼭 해야한다면 순환참조 제거를 위해 @ToString.Exclude 어노테이션을 설정해야한다.
9.4 다대일, 일대다 매핑
그러나 간단한 일대일 매핑보다 보통 다대일 매핑이 많다.
다대일 단방향 매핑
예를 들어 한개의 상품만 존재할 때,
주문 <-> 상품 관계에서 1개의 상품은 여러개의 주문과 연관관계를 맺고있는 것처럼 말이다.
이때는 @ManyToOne 어노테이션을 사용하면 되고 이때는 앞에 Many가 먼저오니까 다대일에서 '多'인 주문 엔티티 클래스의 필드에 상품 엔티티를 넣는다.
@ManyToOne
@JointColumn(name = "상품 이름")
@ToString.Exclude
private Product product;
마찬가지로 여기서 해당 매핑 어노테이션 필드를 갖고있는 주문 엔티티 클래스가 주인이다.
다대일 양방향 매핑
다대일 단방향 연관관계와 달리 다대일 양방향 매핑은 각 엔티티1, 2의 필드에 ManyToOne 어노테이션으로 엔티티2, 엔티티1을 쓰면 된다.
다대일매핑에서 앞전에 다대일 단방향 매핑은 ManyToOne을 사용해서 1인 엔티티를 필드에 써놓았지만
양방향은
1인 엔티티에서 多인 엔티티를 @OneToMany 어노테이션을 사용하고 Many 이므로 List형식으로 저장해놓아야한다.
여기서 OneToMany는 fetch 요소의 기본값이 LAZY이므로 EAGER로 설정해놓은 모습이다.
또한 RDBMS에서 외래키의 형식을 사용하기 위해 앞전에 말한 mappedBy를 설정한 모습이다.
By 뒤에 들어간 provider가 자식 엔티티가 되고 나머지 엔티티가 부모엔티티(Owner)가 된다.
9.5 다대다 매핑
다대다 연관관계는 실무에서 거의 사용되지 않는 구성이다.
그러나 아까 주문과 상품에 대해서 생각해보면 한가지 상품이 아닌 여러가지 상품일 경우
한 종류의 주문이 여러가지 상품을 주문할 수 있고, 한 상품이 여러 개의 주문으로 주문될 수 있는 경우가 다대다 연관관계를 생각 할 수 있다.
다대다 연관관계에서는 각 엔티티에서 서로를 리스트로 갖게 되며
이 때는 교차 엔티티라고 하는 중간 테이블을 생성해서 다대다 관계 -> 일대다 or 다대일 관계로 해소한다.
실제로 JPA에서 중간 테이블을 자동으로 만든다.
9.6 영속성 전이
영속성 전이(cascade)란 특정 엔티티의 영속성 상태를 변경할 때 그 엔티티와 연관관계인 엔티티의 영속성에도 영향을 미쳐 영속성 상태를 변경한다.
아까 OneToOne 어노테이션 인터페이스에서 cascade 요소도 있었는데
이때 cascade의 옵션을 설정할 수 있다.
cascade 옵션
- ALL : 주인인 엔티티가 영속 상태 변경시(영속화, 제외, 병합, 제거, 새로고침 등) 연관관계 엔티티도 동일하게 적용
- PERSIST : 주인인 엔티티가 영속화할 때 연관된 엔티티도 함께 영속화
- MERGE : 주인인 엔티티가 영속성 컨텍스트에 병합할 때 연관된 엔티티도 병합
- REMOVE : 주인인 엔티티를 제거할 때 연관된 엔티티도 제거
- REFRESH : 엔티티를 새로고침할 때 연관된 엔티티도 새로고침
- DETACH : 주인관계인 엔티티를 영속성 컨텍스트에서 제외(삭제)하면 연관된 엔티티도 삭제
cascade 옵션을 잘 사용하면 영속 상태 변화에 따라 연관관계에 있는 엔티티도 동시에 동작을 수행할 수 있어 개발의 생산성을 높일 수 도 있지만,
특히 REMOVE, ALL과 같은 타입은 삭제를 동반하므로 주의해야한다.
고아 객체
고아(orphan)이란 부모 엔티티(Owner)와 연관관계가 끊어진 엔티티를 의미하며 JPA에서는 이러한 고아 객체를 자동으로 제거하는 기능이 있다.
이것 또한 어노테이션의 요소중 orphanRemoval = true를 사용하면된다. 이 때 자식엔티티가 다른 엔티티들과 연관관계를 맺고 있을 경우 고아객체가 될 때 자동으로 삭제해도 되는지 주의해야한다.
'BookStudy > 스프링 부트 핵심 가이드' 카테고리의 다른 글
[스프링 부트 핵심 가이드] 11 액추에이터 활용하기 (1) | 2023.10.08 |
---|---|
[스프링 부트 핵심 가이드] 10 유효성 검사와 예외 처리 (0) | 2023.10.01 |
[스프링 부트 핵심 가이드] 08. Spring Data JPA 활용 (0) | 2023.09.17 |
[스프링 부트 핵심가이드] 06. 데이터베이스 연동 (0) | 2023.09.08 |
[스프링 부트 핵심 가이드] 05. API를 작성하는 다양한 방법 (0) | 2023.08.31 |