
: 스프링 부트를 활용한 애플리케이션 개발 실무
📝 목차
9장. 연관관계 매핑
9-1. 연관관계 매핑 종류와 방향
9-2. 프로젝트 생성
9-3. 일대일 매핑
- 일대일 단방향 매핑
- 일대일 양방향 매핑
9-4. 다대일, 일대다 매핑
- 다대일 단방향 매핑
- 다대일 양방향 매핑
- 일대다 단방향 매핑
9-5. 다대다 매핑
- 다대다 단방향 매핑
- 다대다 양방향 매핑
9-6. 영속성 전이
- 영속성 전이 적용
- 고아 객체
9-7. 정리
테이블의 연관관계를 설정해서 엔티티 간의 연관관계로 표현
객체와 테이블의 성질이 달라 정확한 연관관계를 표현할 수 없다
JPA에서 이러한 제약을 보완하면서 연관관계를 매핑하고 사용하는 방법 알아보자
연관관계를 맺는 두 엔티티 간에 생성할 수 있는 연관관계의 종류
예시로 이해해보자
한 가게가 재고관리 시스템을 통해 상품을 관리
: 상품 테이블과 공급업체 테이블의 관계
✅ 공급업체 입장
➞ 한 가게에 납품하는 상품이 여러개 있을 수 있으므로 상품 엔티티와는 일대다 관계
✅ 상품 입장
➞ 하나의 공급업체에 속하게 되므로 다대일 관계
어떤 엔티티를 중심으로 연관 엔티티를 보느냐에 따라 연관관계의 상태가 달라짐!
데이터베이스에서는 두 테이블의 연관관계를 설정하면 외래키를 통해 서로 조인해서 참조하는 구조로 생성
JPA를 사용하는 객체지향 모델링에서는 엔티티 간 참조방향을 설정할 수 있다.
연관관계가 설정되면 한 테이블에서 다른 테이블의 기본값을 외래키로 갖게 됩니다.
이런 관계에서는 주인(Owner)이라는 개념이 사용됩니다.
일반적으로 외래키를 가진 테이블이 그 관계의 주인이 되며, 주인은 외래키를 사용할 수 있으나 상대 엔티티는 읽는 작업만 수행할 수 있습니다.
One To One : 일대일 (1:1)
: 하나의 상품에 하나의 상품 정보만 매핑되는 구조
✅ @OneToOne 어노테이션
: 다른 엔티티 객체를 필드로 정의했을 때, 일대일 연관관계로 매핑하기 위해 사용
✅ @JoinColumn 어노테이션
: 매핑할 외래키를 설정
@JoinColumn 어노테이션 속성값
☑️ name
: 매핑할 외래키의 이름을 설정
☑️ referencedColumnName
: 외래키가 참조할 상대 테이블의 컬럼명을 지정
☑️ foreignKey
: 외래키를 생성하면서 지정할 제약조건을 설정
(unique, nullable, insertable, updatable등)
즉시 로딩 : 엔티티를 조회할 때 연관된 엔티티도 함께 조회하는 것
: 양쪽에서 단방향으로 서로를 매핑하는 것을 의미
⭐ 양방향으로 연관관계가 설정되면 ToString을 사용할 때 순환참조가 발생
필요한 경우가 아니라면 대체로 단방향으로 연관관계를 설정하거나
양방샹 설정이 필요한 경우에는 순환참조 제거를 위해 exclude를 사용해 ToString에서 제외설정을 하기
상품 테이블과 공급업체 테이블을 예시로
상품 테이블 입장에서는 다대일
공급업체 테이블의 입장에서 볼 때는 일대다 관계로 볼 수 있다.
🍀 Tip. 지연로딩과 즉시로딩
지연로딩(lazy loading), 즉시로딩(eager loading)
엔티티라는 객체의 개념으로 데이터베이스를 구현했기 때문에
연관관계를 가진 각 엔티티 클래스에는 연관관계가 있는 객체들이 필드에 존재하게 됩니다.
연관관계와 상관없이 즉각 해당 엔티티의 값만 조회하고 싶거나
연관관계를 가진 테이블의 값도 조회하고 싶은 경우 등 여러조건들을 만족하기 위해 등장한 개념
-> 지연로딩과 즉시로딩
@OneToMany와 @JoinColumn을 사용하면 상품 엔티티에서 별도의 설정을 하지 않아도 일대다 단방향 연관관계가 매핑됩니다.
✅ @JoinColumn 어노테이션 ⭢ 필수 사항은 아니다.
이 어노테이션을 사용하지 않으면 중간 테이블로 Join테이블이 생성되는 전략 채택
: 다대다 연관관계는 실무에서 거의 사용되지 않는 구성입니다.
예를 들면, 한 종류의 상품이 여러 생산업체를 통해 생산 될 수 있고,
생산업체 한 곳이 여러 상품을 생산 할 수도 있습니다.
다대다 연관관계에서는 각 엔티티에서 서로를 리스트로 가지는 구조
이런 경우에는 교차 엔티티라고 부르는 ⭐중간 테이블⭐을 생성해서 다대다 관계를 일대다 또는 다대일 관계로 해소합니다.
@ManyToMany 어코테이션으로 설정으로 설정
리스트로 필드를 가지는 객체에서는 외래키를 가지지 않기 때문에 별도의 @JoinColumn은 설정하지 않아도 된다.
다대다 연관관계 설정 ⭢ 중간 테이블을 통해 연관된 엔티티의 값을 가져올 수 있다
<다대다 양방향 매핑의 한계>
다대다 연관관계에서는 중간 테이블이 생성되기 때문에 예기치 못한 쿼리가 생길 수 있다. = 관리하기 힘들다.
✅ 중간테이블을 생성하는 대신, 일대다 다대일로 연관관계를 맺을 수 있는 중간 엔티티로 승격시켜 JPA에서 관리하도록 생성하는 게 좋다.
: 특정 엔티티의 영속성 상태를 변경할 때,
그 엔티티와 연관된 엔티티의 영속성에도 영향을 미쳐 영속성 상태를 변경하는 것
예를 들어
@OneToMany어노테이션의 인터페이스 살펴보기
연관관계와 관련된 어노테이션을 보면 cascade() 요소를 볼 수 있다.
이 어노테이션은 영속성 전이를 설정하는 데 활용된다.
| 종류 | 설명 |
|---|---|
| ALL | 모든 영속 상태 변경에 대해 영속성 전이를 적용 |
| PERIST | 엔티티가 영속화할 때 연관된 엔티티도 함께 영속화 |
| MERGE | 엔티티를 영속성 컨텍스트에 병합할 때 연관된 엔티티도 병합 |
| REMOVE | 엔티티를 제거할 때 연관된 엔티티도 제거 |
| REFRESH | 엔티티를 새로고침할 때 연관된 엔티티도 새로고침 |
| DETACH | 엔티티를 영속성 컨텍스트에서 제외하면 연관된 엔티티도 제외 |
영속성 전이에 사용되는 타입은 엔티티 생명주기와 연관이 있습니다.
한 엔티티가 cascade 요소의 값으로 주어진 영속 상태의 변경이 일어나면
매핑으로 연관된 엔티티에도 동일한 동작이 일어나도록 전이를 발생시키는 것 입니다.
✅ 영속성의 전이 사용 전 ⭢ 엔티티를 데이터베이스에 저장하기 위해 각 엔티티를 저장하는 코드를 작성해야 함
✅ 영속성 전이 사용 ⭢ 부모 엔티티가 되는 엔티티만 저장하면 코드에 작성돼 있는 Cascade.PERSIST에 맞춰 상품 엔티티도 함께 저장할 수 있음
이처럼 특정 상황에 맞춰 영속성 전이 타입을 설정하면
영속 상태의 변화에 따라 연관된 엔티티들의 동작도 함께 수행할 수 있어 ⭐개발의 생산성 증대
<사용 시 주의할 점>
자동 설정으로 동작하는 코드들이 정확히 어떤 영향을 미치는지 반드시 파악할 것
예를 들어,
REMOVE와 REMOVE를 포함하는 ALL같은 타입은 연관된 엔티티가 의도치 않게 모두 삭제될 위험성이 있어 다른 타입보다 더욱 사이드 이펙트(side effect)를 고려해서 사용해야 한다.
: JPA에서 고아(orphan)란 부모 엔티티와 연관관계가 끊어진 엔티티를 의미
JPA에는 이러한 고아 객체들을 자동으로 제거하는 기능이 존재
고아 객체를 제거하는 기능을 사용하려면
@OneToMany 어노테이션 속성에 orphanRemoval속성을 true로 설정