* Mac사용, Java17 사용
* 진도 : 섹션2-(1) ~ (4)
* : 자바 클래스명, : 코드, : 단축키
1. 요구사항 분석
- 회원
- 회원 등록
- 회원 조회 상품 기능
- 상품
- 상품 등록
- 상품 수정
- 상품 조회
- 주문
- 상품 주문
- 주문 내역 조회
- 주문 취소
- 기타
- 상품은 재고 관리 필요
- 상품의 종류 : 도서, 음반, 영화
- 상품을 카테고리로 구분 가능
- 상품 주문시 배송 정보 입력
2. 도메인 모델과 테이블 설계
1) 테이블
- 회원 / 주문 / 배송 / 주문 상품 / 카테고리 / 상품 / 배송 / 도서, 음반, 영화
< 회원 - 주문 >
- 회원은 여러 상품을 주문할 수 있다 = 1:N
< 주문 - 배송 >
- 주문할 때 배송정보 필요 = 1:1
< 주문 - 주문한 상품 - 상품 >
- 한 번 주문할 때 여러 상품을 주문할 수 있고 하나의 상품이 여러 주문에 담길 수 있다 = N:N
- < 주문 - 주문한 상품 > = 1:N / < 주문한 상품 - 상품 > = N : 1
- 다대다 관계는 좋지 않아서 1:N 혹은 N:1 관계로 변경하는게 좋다 → 주문상품 엔티티 추가
< 상품 - 카테고리에 있는 상품 - 카테고리 >
- 하나의 상픔이 여러 카테고리에 들어갈 수 있고 하나의 카테고리에 여러 상품이 들어갈 수 있다 = N:N
- 다대다 관계는 좋지 않아서 1:N 혹은 N:1 관계로 변경하는게 좋다 → 카테고리에 있는 상품 엔티티 추가
< 상품의 종류_도서, 음반, 영화 >
- 상품이라는 공통 속성을 사용하므로 상속 구조로 표현
2) ERD 및 연관관계 매핑 분석

< member > | < orders > | < order_item > | < item > |
|
|
|
|
< category > | < category_item > | < delivery > | < address > |
|
|
|
|
- 1:N에서의 FK는 무조건 N에 있다
- 1:N, N:N의 양방향 관계는 주인을 정해야한다 (외래키가 있는 테이블을 연관 관계 주인으로 정하는 것이 좋다)
- 연관관계 주인에서 셋팅해야 값이 변경된다
< member - orders > 1:N (양방항) 주문 테이블 → 외래키 갖고 있다 → 주인 = ORDERS.member_id 외래 키와 매핑 < orders - order_item > 1:N (양방향) 주문_상품 테이블 → 외래 키 갖고 있다 → 연관관계의 주인 = ORDER_ITEM.order_id 외래 키와 매핑 < order_item - item > N:1 나를 주문한 odrder_item 모두 찾아! 이런 경우는 없으니 단방향 = ORDER_ITEM.item_id 외래 키와 매핑 |
< orders - delivery > 1:1 (양방항) 주문 테이블 → 외래키 갖고 있다 → 주인 = ORDERS.delivery_id 외래 키와 매핑 < item - category_item > 1:N 카테고리_상품 테이블 → 외래키 갖고 있다 → 주인 = CATEGORY_ITEM.item_id 외래 키와 매핑 < category_item - category > N:1 카테고리_상품 테이블 → 외래키 갖고 있다 → 주인 =CATEGORY_ITEM.category_id 외래 키와 매핑 |
3. 엔티티 클래스 개발
1) Member [ src - java - jpabook.jpashop - domain - Member ]
- 엔티티, 롬복 사용 @Entity @Getter @Setter
- 기본키 생성 및 전략 @Id @GeneratedValue
- 테이블의 컬럼과 연결될 대상에 '표시' @Column(name = "member_id")
- 테이블(클래스)의 ID와 외래키 컬럼의 이름을 동일하게 맞춰주기 위해
- 필드 생성 private ~
- id, name
- id, name
- JPA 내장 타입 (사용하는 곳에 표시) @Embedded → Address
- 위처럼 쓰든지 address 클래스가서 @Embeddable 쓰든지 둘 중 하나만 써도 괜춘
- 필드 생성 private ~
- Address address
- Address address
- 1:N 관계 (member 입장에서)' @OneToMany(mappedBy = "member")
- 하나의 회원이 여러개의 상품 주문 = 1:N
- member 연관관계 주인X / order에서 가져다 씀 = mappedBy사용
- 필드 생성 private ~
- orders(list)
- orders(list)
2) Address [ src - java - jpabook.jpashop - domain - Address ]
- JPA 내장 타입 (정의하는 곳에 표시) @Embeddable
- 필드 생성 private ~
- city, street, zipcode
- city, street, zipcode
- 기본 생성자 protected ~ (command + N)
-
값 타입은 변경 불가능하게 설계해야 하므로 @Setter 지우고 기본생성자로 초기화한다
public을 protected로 수정하는 것이 더 안전
-
- 전체 생성자 public ~ (command + N)_모두 선택
3) Order [ src - java - jpabook.jpashop - domain - Order ]
- 엔티티, 롬복 사용 @Entity @Getter @Setter
- 엔티티와 매핑할 테이블을 지정 @Table(name"orders")
- 기본키 생성 및 전략 @Id @GeneratedValue
- 테이블의 컬럼과 연결될 대상에 '표시' @Column(name = "order_id")
- 테이블(클래스)의 ID와 외래키 컬럼의 이름을 동일하게 맞춰주기 위해
- 필드 생성 private ~
- id , orderDate
- N : 1 관계 (order 입장에서)'@ManyToOne
- FK @JoinColumn(name = "member_id")
- order가 연관관계 주인
- 필드 생성 private ~
- Member member
- 1 : N 관계 (order 입장에서) @OneToMany(mappedBy = "order")
- order 연관관계 주인X / orderItem에서 가져다 씀 = mappedBy사용
- 필드 생성 private ~
- orderitems(list)
- 1 : 1 관계 @OneToOne
- FK @JoinColumn(name = "delivery_id")
- 1:1 관계는 FK 어디에 둬도 상관없지만 주로 엑세스 많이 하는 곳에 두기
- 필드 생성 private ~
- Delivery delivery
- enum 타입을 매핑 @Enumerated(EnumType.STRING)
- EnumType.ORDINAL : enum 순서를 데이터베이스에 저장
EnumType.STRING : enum 이름을 데이터베이스에 저장 - 필드 생성 private ~
- Orderstatus orderstatus
- Orderstatus orderstatus
- 연관관계 메서드
4) OrderItem [ src - java - jpabook.jpashop - domain - OrderItem ]
- 엔티티, 롬복 사용 @Entity @Getter @Setter
- 엔티티와 매핑할 테이블을 지정 @Table(name"order_item")
- 기본키 생성 및 전략 @Id @GeneratedValue
- 테이블의 컬럼과 연결될 대상에 '표시' @Column(name = "order_item_id")
- 테이블(클래스)의 ID와 외래키 컬럼의 이름을 동일하게 맞춰주기 위해
- 필드 생성 private ~
- id
- id
- N : 1 관계 (OrderItem 입장에서)'@ManyToOne
- FK @JoinColumn(name = "item_id")
- order가 연관관계 주인
- 필드 생성 private ~
- Item item
- Item item
- N : 1 관계 (OrderItem 입장에서)'@ManyToOne
- FK @JoinColumn(name = "order_id")
- order가 연관관계 주인
- 필드 생성 private ~
- Order order, orderPrice, count
- Order order, orderPrice, count
5) enum
OrderStatus [ src - java - jpabook.jpashop - domain - OrderStatus ]
ORDER, CANCEL
DeliveryStatus [ src - java - jpabook.jpashop - domain - DeliveryStatus ]
READY, COMP
6) Item [ src - java - jpabook.jpashop - domain - Item ]
- 엔티티, 롬복 사용 @Entity @Getter @Setter
- 부모클래스에 상속 매핑 @Inheritance(~SINGLE_TABLE)
싱글테이블 전략 InheritanceType.SINGLE_TABLE
장점 - 조인 필요 없어서 조회 성능이 빠르고 조회 쿼리가 단순
단점 - 매핑한 컬럼은 모두 null 허용, 단일 테이블에 모든 것을 저장하므로 테이블이 커져 오히려 성능 느려질 수도 있다
주의 - 구분 컬럼을 꼭 사용하기 ( @DiscriminatorColumn )
- 부모클래스에 구분칼럼 지정 @DiscriminatorColumn(name="dtype")
- 추상관계 public abstract ~
- 기본키 생성 및 전략 @Id @GeneratedValue
- 테이블의 컬럼과 연결될 대상에 '표시' @Column(name = "tem_id")
- 테이블(클래스)의 ID와 외래키 컬럼의 이름을 동일하게 맞춰주기 위해
- 필드 생성 private ~
- id, name, price, stockQuantity
- id, name, price, stockQuantity
- N : N 관계 @ManyToMany(mappedBy = "items")
- 테이블(클래스)의 ID와 외래키 컬럼의 이름을 동일하게 맞춰주기 위해
- 필드 생성 private ~
- category(list)
- category(list)
7) Item 상속 디렉토리
Album [ src - java - jpabook.jpashop - domain - item - Album ]
- 엔티티, 롬복 사용 @Entity @Getter @Setter
- 구분 컬럼 Dtype에 저장할 값 @DiscriminatorValue("A")
- Item에 상속됨 @~extends Item
- 필드 생성 private ~
- artist, etc
- artist, etc
Book [ src - java - jpabook.jpashop - domain - item - Book ]
- 엔티티, 롬복 사용 @Entity @Getter @Setter
- 구분 컬럼 Dtype에 저장할 값 @DiscriminatorValue("B")
- Item에 상속됨 @~extends Item
- 필드 생성 private ~
- author, isbn
- author, isbn
Movie [ src - java - jpabook.jpashop - domain - item - Movie ]
- 엔티티, 롬복 사용 @Entity @Getter @Setter
- 구분 컬럼 Dtype에 저장할 값 @DiscriminatorValue("M")
- Item에 상속 @~extends Item
- 필드 생성 private ~
- director, actor
- director, actor
8) Delivery [ src - java - jpabook.jpashop - domain - Delivery ]
- 엔티티, 롬복 사용 @Entity @Getter @Setter
- 기본키 생성 및 전략 @Id @GeneratedValue
- 테이블의 컬럼과 연결될 대상에 '표시' @Column(name = "delivery_id")
- 테이블(클래스)의 ID와 외래키 컬럼의 이름을 동일하게 맞춰주기 위해
- 필드 생성 private ~
- id
- 1 : 1 관계 @OneToOne(mapped by = "delivery")
- 1:1 관계는 FK 어디에 둬도 상관없지만 주로 엑세스 많이 하는 곳에 두기
- delivery 연관관계 주인X / order에서 가져다 씀 = mappedBy사용
- 필드 생성 private ~
- Order order
- JPA 내장 타입 (사용하는 곳에 표시) @Embedded → Address
- 위처럼 쓰든지 address 클래스가서 @Embeddable 쓰든지 둘 중 하나만 써도 괜춘
- 필드 생성 private ~
- Address address
- Address address
- enum 타입을 매핑 @Enumerated(EnumType.STRING)
- EnumType.ORDINAL : enum 순서를 데이터베이스에 저장
EnumType.STRING : enum 이름을 데이터베이스에 저장 - 필드 생성 private ~
- Deliverystatus deliverystatus
- Deliverystatus deliverystatus
9) Category [ src - java - jpabook.jpashop - domain - Category ]
- 엔티티, 롬복 사용 @Entity @Getter @Setter
- 기본키 생성 및 전략 @Id @GeneratedValue
- 테이블의 컬럼과 연결될 대상에 '표시' @Column(name = "category_id")
- 테이블(클래스)의 ID와 외래키 컬럼의 이름을 동일하게 맞춰주기 위해
- 필드 생성 private ~
- id, name
- id, name
- N : N 관계 @ManyToMany
- FK @JoinTable(name = "category_item")
- 외의 코드는 현업에서 안쓰기 땜에 다 적지 않았음 (N:N 은 참고만 하고 사실상 볼 필요없음)
- 필드 생성 private ~
- items(list)
- items(list)
- 연관 관계 설정
10) 실행 결과 [src - java - jpabook.jpashop -CJpaShopApplication ]
[출처] 김영한 강사님 인프런 스프링 JPA 1편
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 - 인프런 | 강의
실무에 가까운 예제로, 스프링 부트와 JPA를 활용해서 웹 애플리케이션을 설계하고 개발합니다. 이 과정을 통해 스프링 부트와 JPA를 실무에서 어떻게 활용해야 하는지 이해할 수 있습니다., 스프
www.inflearn.com
'Spring > 스프링 JPA 활용' 카테고리의 다른 글
[스프링 JPA 1편] 2 - 2) 엔티티 설계 시 주의점 (0) | 2023.12.12 |
---|---|
[스프링 JPA 1편] 1 - (1) 프로젝트 생성 (0) | 2023.12.12 |