Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- dfs
- 가상컴퓨팅
- generic class
- 자바의정석
- DB
- 크루스칼
- dbms
- jsp
- 생성자
- data structure
- 공개키 암호화
- 알고리즘
- cloud computing
- 코딩테스트
- Queue
- python
- JPA
- sql
- Stack
- javascript
- 암호학
- 클라우드 컴퓨팅
- Java
- spring
- 자료구조
- BFS
- JDBC
- 코테
- MVC
- Algorithm
Archives
- Today
- Total
PLOD
[Spring] 연관 관계 매핑 본문
- ※ 이 글은 '스프링 부트 쇼핑몰 프로젝트 with JPA' 책을 참고하여 적은 글입니다.
지금처럼 이커머스를 기준으로 프로젝트를 진행할 때 장바구니(위시리스트)와 상품과 회원은 무조건 존재해야 될 엔티티이다.
연관관계
- 객체 지향 프로그래밍의 세계와 관계형 데이터베이스의 세계를 연결해주는 개념
- 객체 간의 관계를 데이터베이스의 테이블과 매핑하기 위한 규칙과 방법을 제공
연관관계 매핑의 종류는 다음과 같다
- 일대일(1:1) : @OneToOne
- 일대다(1:N) : @OneToMany
- 다대일(N:1) : @ManyToOne
- 다대다(N:M) : @ManyToMany
엔티티를 매핑할 때는 방향성을 고려해야 한다. 테이블에서의 관계는 항상 양방향이지만, 객체에서는 단방향과 양방향이 존재한다.
1. 단방향 연관관계
- 단방향 연관관계는 한쪽에서만 관계를 설정한 경우이다
- A 엔티티가 B 엔티티를 참조하지만, B는 A를 참조하지 않는 경우
일대일 단방향 매핑
@Table(name = "cart")
@Entity
@Getter
@Setter
@ToString
public class Cart {
@Id
@Column(name = "cart_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne // one-to-one mapping 이나 many-to-one mapping 은 기본적으로 EAGER 로딩이다.
@JoinColumn(name = "member_id")
private Member member;
}
장바구니와 회원은 일대일로 매핑되어 있으며, 장바구니 엔티티가 회원 엔티티를 참조하는 일대일 단방향 매핑이다
다대일 단방향 매핑
@Table(name = "cart_item")
@Entity
@Getter
@Setter
@ToString
public class CartItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cart_item_id")
private Long id;
@ManyToOne
@JoinColumn(name = "cart_id")
private Cart cart;
@ManyToOne
@JoinColumn(name = "item_id")
private Item item;
private int count;
}
- 하나의 장바구니에는 여러 개의 상품을 담을 수 있으므로 @ManyToOne
- 하나의 상품은 여러 장바구니의 장바구니 상품으로 담길수 있으므로 @ManyToOne
2. 양방향 연관관계
- 양방향 연관관계는 두 엔티티가 서로를 참조하는 경우(서로 단방향 매핑)
- 양방향 관계에서는 객체의 관계뿐만 아니라 데이터베이스의 외래 키 제약 조건을 설정하는 방식도 고려헤야 함
@Table(name = "orders") // order 키워드가 있기 때문에 테이블을 orders로 지정
@Getter
@Setter
@Entity
public class Order {
@Id
@Column(name = "order_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
private LocalDateTime orderDate;
@Enumerated(EnumType.STRING)
private OrderStatus orderStatus;
private LocalDateTime regTime;
private LocalDateTime updateTime;
}
한명의 회원은 여러번 주문을 할 수 있으므로 다대일 단방향 매핑
@Table(name = "order_item")
@Getter
@Setter
@Entity
public class OrderItem {
@Id
@Column(name = "order_item_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "item_id")
private Item item;
@ManyToOne
@JoinColumn(name = "order_id")
private Order order;
private int orderPrice;
private int count;
private LocalDateTime regTime;
private LocalDateTime updateTime;
}
- 하나의 상품은 여러 주문 상품에 포함될 수 있기 때문에 item 기준으로 다대일 단방향 매핑
- 한 번의 주문에 여러 개의 상품을 주문할 수 있으므로 order 기준으로 다대일 단방향 매핑
※ 연관관계파악 tip
위의 상황처럼 주문 상품과 주문 엔티티 사이에 연관관계를 파악할 때 필자는 처음에 어느 쪽이 多인지 헷갈리는 경우가 있었다.
물론 지금과 같이 이커머스와 같은 상황은 엔티티가 정형화되어 있어서 외우면 된다지만 앞으로 현업에서는 다양한 상황의 엔티티의 매핑을 고려해야 한다. 이럴 때는 엔티티 하나를 기준으로 생각해서 가정해보면 된다
ex) 하나의 상품(One) → 여러개의 주문 상품(Many)
public class OrderItem {
@ManyToOne
@JoinColumn(name = "item_id")
private Item item;
}
ex) 하나의 주문(One) → 여러 개의 주문 상품(Many)
public class OrderItem {
@ManyToOne
@JoinColumn(name = "order_id")
private Order order;
}
양방향 관계에서의 주의점:
- 연관관계의 주인 (Owner): JPA에서는 외래 키를 관리하는 주체가 필요
- @ManyToOne 쪽이 기본적으로 관계의 주인(반대로 @OneToMany(mappedBy = "---")는 주인이 아니다)
- 연관관계의 주인은 외래 키를 관리하고, 주인이 아닌 엔티티는 읽기 전용
다대다 매핑(@ManyToMany), N:M를 해소하는 중간 테이블
다대다 관계의 경우 그대로 사용하지 못하고 반드시 데이터베이스 정규화를 통해 중간 테이블을 만들어 줘야 한다.
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToMany
@JoinTable(name = "새로 만들어줄 중간 테이블 이름")
private List<Product> products = new ArrayList<>();
}
.
.
.
@Entity
public class Product {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToMany(mappedBy = "products")
private List<Member> members = new ArrayList<>();
}
- 데이터베이스 테이블 간의 양방향 관계를 지원해주는 @ManytoMany 어노테이션이 존재하지만 실무에서는 이를 사용하는 것을. 지양하고 있다.
- 중간테이블을 만들고 PK, FK 쌍을 알아서 매핑해주는 것까지 문제가 없는데 실무 레벨에서는 이러한 테이블 매핑에 필요한 필수적인 정보들 외에도 중간 테이블이 가져가야 하는 여러 가지 컬럼들이 있을 수 있다.
- hibernate에 의해 생성된 중간 테이블은 관계 설정에 필수적으로 필요한 정보들만 담겨있을 뿐 이러한 비즈니스 로직상 필요한 정보들은 담기지 않는다.
- 다대다 관계를 사용하고 싶은 경우라면 중간 테이블에 대한 클래스를 직접 만들어서 @ManyToOne과 @OneToMany의 조합을 만들어 사용해야 한다.
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@OneToMany(mappedBy = "member")
private List<MemberProduct> memberProducts = new ArrayList<>();
}
.
.
.
@Entity
public class Product {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "product")
private List<MemberProduct> memberProducts = new ArrayList<>();
}
.
.
.
@Entity
public class MemberProduct {
@Id @GeneratedValue
private Long id;
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
@ManyToOne
@JoinColumn(name = "PRODUCT_ID")
private Product product;
}
'개발 공부 > Spring framework' 카테고리의 다른 글
[Spring] Redis 캐싱을 사용한 상품 정보 조회 성능 향상 (0) | 2024.10.03 |
---|---|
[Spring] 재고시스템으로 알아보는 동시성 이유 (1) | 2024.10.03 |
[Spring] MSA(MicroService Architecture) (0) | 2024.08.20 |
[Spring] @Request Param , @PathVariable과 Mapping 정리 (0) | 2024.08.17 |
[Spring] 3 Layer Architecture (0) | 2024.07.29 |
Comments