1. 요구사항 분석
1) 회원 기능
- 회원 등록
- 회원 조회
2) 상품 기능
- 상품 등록
- 상품 수정
- 상품 조회
3) 주문 기능
- 상품 주문
- 주문 내역 조회
- 주문 취소
4) 기타 요구사항
- 상품은 재고 관리가 필요하다.
- 상품의 종류는 도서, 음반, 영화가 있다.
- 상품을 카테고리로 구분할 수 있다.
- 상품 주문시 배송 정보를 입력할 수 있다.
2. 도메인 모델과 테이블 설계

- 다대다 관계는 관계형 데이터베이스는 물론, 엔티티에서도 거의 사용하지 않는다.
따라서 '주문상품'이라는 엔티티를 추가해서 일대다, 다대일 관계로 풀어냈다.
3. 회원 엔티티 분석

- 실무에서는 회원이 주문을 참조하지 않고, 주문이 회원을 참조하는 것으로 충분하다.
('多'에서 '一'을 참조한다.)
→ 주문내역이 필요할 경우의 쿼리를 생각했을 때,
Member 내의 리스트로 주문을 찾아오는 것이 아니라
Order내의 필터링 조건으로 멤버가 들어간다.
+. Entity 클래스 내의 field 값을 의미한다.
+. 모든 클래스에는 공통적으로 Primary Key를 생성하는 ID가 있다.
4. 회원 테이블 분석

- 테이블명이 「ORDERS」인 것은 데이터베이스가 「order by」를 예약어로 사용하는 경우가 많다.
그래서 관례상 「ORDERS」를 많이 사용한다.
- 데이터베이스 테이블명, 컬럼명에 대한 관례는 "소문자 + _" 스타일로 일관성 있게 사용한다.
+. DB 내의 저장되는 column 값을 의미한다.
+. Item과 Category의 경우 중간에 맵핑 테이블을 두고, 일대다 다대일 관계로 풀고 있다.
5. 연관관계 매핑 분석
- "양방향 관계"일 경우, 외래 키가 있는 곳을 연관관계의 주인으로 정하자.
→ 연관관계의 주인은 단순히 외래 키를 누가 관리하냐의 문제이지, 비즈니스 상 우위에 있다고 주인으로 정하면 안된다.
+. 외래 키가 있는 곳은 항상 多
+. 연관관계의 주인
: JPA는 연관관계의 주인을 중심으로, 변경을 감지 후 FK를 업데이트 한다. (객체는 두 군데 모두 변경되게끔 코드 작성해야 함)
6. 엔티티 클래스 개발
- 실무에서는 가급적 Getter는 열어두고, Setter는 꼭 필요한 경우에만 사용
- 실무에서는 @ManyToMany를 사용 x
- 중간 테이블에 컬럼을 추가할 수 없고, 세밀하게 쿼리를 실행하기 어렵다는 한계가 있다.
따라서 중간 엔티티를 만들고 @ManyToOne, @OneToMany로 매핑해서 사용하자!

- 값 타입은 변경 불가능하게 설계해야 한다.
- @Setter를 사용하지 않고, 생성자에서 값을 모두 초기화해서 변경 불가능한 클래스를 만들자.
- JPA 스펙상, 엔티티나 임베디드 타입은 기본 생성자를 protected로 설정하는 것이 안전하다.
(개발을 하면서, 기본 생성자 호출을 막고 '사용자 정의 생성자'를 사용하기 위함)
+. EnumType.STRING으로 두자
(Original은 sequential 하게 설정되는데, 중간에 삭제될 시 공백이 생김)
+. 일대일 관계에서는 주로 액세스를 많이 하는 곳에 FK를 두자
+. 서로 엮여 있는 카테고리를 만들기 위해, 셀프로 양방향 연관관계를 만들었다.

+. 엔티티나 임베디드 타입은 자바 기본 생성자를 public 또는 Protected로 설정하자.
- jpa 구현 라이브러리가 객체를 생성할 때 리플랙션 같은 기술을 사용할 수 있도록 지원해야 하기 때문
7. 엔티티 설계 시 주의점
실무에서, 모든 연관관계는 "지연로딩(LAZY)"으로 설정하자
- @XToOne(OneToOne, ManyToOne) 관계는 기본이 즉시로딩이므로, 직접 지연로딩으로 설정해야 한다.
- 즉시로딩(EAGER)은 예측이 어렵고, 어떤 SQL이 실행될지 추적하기 어렵다.
특히 JPQL을 실행할 때 N+1 문제가 자주 발생한다.
- 연관된 엔티티를 함께 DB에서 조회해야 하면, fetch join 또는 엔티티 그래프 기능을 사용한다.
컬렉션은 필드에서 초기화 하는 것이 안전하다.
- null 문제
- Hibernate는 엔티티를 영속화 할 때, 컬렉션을 감싸서 하이버네이트가 제공하는 내장 컬렉션으로 변경한다.
- 컬렉션 자체를 바꾸지 마라(?)
Q. 필드에 있는 컬렉션을 초기화 시키는 이유가 뭔가요?
테이블, 컬럼명 생성 전략
SpringPhysicalNamingStrategy [Default]
: 엔티티의 필드명 그대로 테이블의 컬럼명으로 사용
1) 엔티티는 그대로 테이블 명으로 사용
2) 엔티티(필드) → 테이블(컬럼)
- .(점) → _(언더스코어)
- 대문자 → 소문자
+. CascadeType
해당 Entity를 persist 할 때, cascade 한 필드 값도 같이 persist 해준다.
+. 연관관계 편의 메서드
# Order 클래스
# 양방향으로 설정
# 데이터베이스에 저장하는 것은, 외래키 위치만 잘 선정해 저장하면 되지만
# 엔티티를 설계할 때, 상태 변화를 양방향에서 변경시켜줘야 한다. (양방향 관계)
public void setMember(Member member){
this.member = member # order 클래스 필드 member에, member 주입
member.getOrder.add(this) # member 내의 List<order>에는, order(this) 주입
}
public void addOrderItem(OrderItem orderItem){
orderItems.add(orderItem) # order 클래스 필드 List<OrderItem>에는, orderItem 주입
orderItem.setOrder(this) # orderItem에는, order(this) 주입
}
public void setDelivery(Delivery delivery){
this.delivery = delivery # order 클래스 필드 delivery에는, delivery 주입
delivery.setOrder(this) # delivery에는, order(this) 주입
}
# Category 클래스
public void addCategory(Category category){
child.add(category) # this 자식으로, category 주입
category.setParent(this) # category의 부모로, category(this) 주입
# 또는
parent = category # this 부모로, category 주입
category.getChild().add(this) # category의 자식으로, this 주입
}
'Spring > JPA 1' 카테고리의 다른 글
6. 주문 도메인 개발 (0) | 2023.11.07 |
---|---|
5. 상품 도메인 개발 (0) | 2023.11.06 |
4. 회원 도메인 개발 (0) | 2023.11.06 |
3. 애플리케이션 구현 준비 (0) | 2023.11.06 |
1. 프로젝트 환경설정 (0) | 2023.08.16 |