본문 바로가기
Spring Framework/Spring Boot

[Spring Boot] 쇼핑몰 #3 - 엔티티 클래스 개발

by JooRi 2024. 10. 8.
728x90
SMALL

2024.10.07 - [Spring Framework/Spring Boot] - 도메인 모델과 테이블 설계

 

도메인 모델과 테이블 설계

* 요구사항 분석회원 기능회원 등록회원 조회상품 기능상품 등록상품 수정상품 조회주문 기능상품 주문주문 내역 조회주문 취소기타 요구사항상품은 재고 관리가 필요하다.상품의 종류는 도서

djjin02.tistory.com

 

 

* 테이블 설계

테이블 설계

 

* Member 엔티티 - 회원 정보 저장

Member.java

 

@Column(name="member_id")

JPA에서 필드와 DB 테이블의 컬럼을 매핑할 때 사용하는 어노테이션이다.

Member 테이블의 id 필드는 Order 테이블의 member_id(외래키)라는 컬럼과 연결된다.

 

@Embedded

JPA에서 내장 타입을 나타내는 어노테이션이다.

이 필드가 다른 엔티티 클래스처럼 별도의 테이블에 매핑되지 않고 해당 엔티티의 일부로서, 같은 테이블에 포함된다.

Address는 별도의 테이블인 독립적 엔티티가 아닌, Member 테이블의 일부이다.

 

@OneToMany

Member 테이블과 Order 테이블이 일대다 관계를 가진다. 회원 한 명은 여러 개의 주문을 가질 수 있다.

 

(mappedBy="member")

어떤 필드가 연관관계의 주인인지, 어느 필드가 연관 관계를 매핑하는 역할을 하는지 하는 데 사용된다.

member는 Order(주문) 테이블에 있는 필드 중 하나이며, 이 필드가 연관관계의 주인이다.

 

List<Order> orders 

회원(Member)과 관련된 주문(Order)들의 목록을 나타낸다. 회원이 주문을 하면 orders 리스트에 Order 객체가 추가된다.

여러 개의 Order 객체를 저장하기 위해 List<Order>을 사용했다.

 

new ArrayList<>()

주문 내역이 없는 상태에서 주문을 조회하면 에러가 발생할 수 있다.

즉, null 상태에서 발생할 수 있는 오류를 방지하기 위해 빈 리스트로 초기화해 둔다.

 

* Order 엔티티 - 주문 정보 저장

@Entity
@Table(name = "orders")
@Getter @Setter
public class Order {

    @Id @GeneratedValue
    @Column(name = "order_id")
    private long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "member_id")
    private Member member;  // 주문 회원

    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderItem> orderItems = new ArrayList<>();

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "delivery_id")
    private Delivery delivery;  // 배송 정보

    private LocalDateTime orderDate;  // 주문 시간

    @Enumerated(EnumType.STRING)
    private OrderStatus status;  // 주문 상태(ORDER/CANCEL)

    // 연관관계 메서드
    public void setMember(Member member) {
        this.member = member;
        member.getOrders().add(this);
    }
    public void addOrderItem(OrderItem orderItem) {
        orderItems.add(orderItem);
        orderItem.setOrder(this);
    }
    public void setDelivery(Delivery delivery) {
        this.delivery = delivery;
        delivery.setOrder(this);
    }
}

 

@Table(name="orders)

Order 엔티티가 orders 테이블과 매핑된다.

테이블명이 클래스명과 다르기 때문에 @Table을 사용해 명시적으로 설정하였다.

 

@JoinColumn(name="member_id")

JPA에서 외래키를 지정하는 어노테이션이다.

member_id는 외래키로 사용되어 orders 테이블(현재 엔티티)에서 member 테이블(Member 엔티티) 연결된다.

 

  @Column @JoinColumn
사용 목적 필드와 DB 컬럼을 단순 매핑 엔티티 간 연관 관계를 설정할 때 외래키 정의 및 매핑
매핑 엔티티의 단순 필드를 DB의 컬럼과 연결 외래키로 사용될 컬럼을 정의하고 다른 엔티티와 연결

 

  @JoinColumn mappedBy
사용 대상 연관 관계 주인 엔티티에서 사용 연관 관계 비주인 엔티티에서 사용
외래키 관리 외래키를 직접 관리 외래키를 관리하지 않고 연관된 주인 엔티티에서 참조
연관 관계 설정 어느 컬럼이 외래키로 사용될지 지정 연관 관계의 주인이 되는 필드 지정
작동 방식 외래키를 통해 연관 관계 설정 주인 엔티티의 필드로 관계 매핑

 

@JoinColumn(name="delivery_id")

현재 엔티티(Order)에서 다른 엔티티(Delivery)와 delivery_id 외래키로 관계를 가진다.

orders 테이블에는 delivery_id라는 컬럼이 존재하며, 이 컬럼은 delivery 테이블의 기본키(id)를 참조하는 외래키가 된다.

→ 특정 주문에 대해 해당 주문의 배송 정보를 참조할 수 있다.

 

@Enumerated(EnumType.STRING)

JPA에서 열거형(enum) 타입의 필드를 어떻게 DB에 저장할 것인지 지정하는 어노테이션이다.

EnumType.STRING은 enum의 이름을 문자열로 DB에 저장한다.

 

* OrderStatus 엔티티 - 주문 상태 정보

OrderStatus.java

 

* OrderItem 엔티티 - 주문 상품 정보

OrderItem.java

 

fetch = FetchType.LAZY

성능 최적화를 위한 관련된 엔티티를 실제로 사용할 때만 조회하여 불필요한 DB접근을 줄이는 전략이다.

지연 로딩(Lazy Loading)을 사용하여 연관된 Item 객체를 실제로 사용할 때만 조회한다.

 

모든 연관관계는 지연로딩으로 설정해야한다.

  • 즉시 로딩(EAGER)은 예측이 어렵고, 어떤 SQL이 실행될지 추적하기 어렵다.
  • 실무에서 모든 연관관계는 지연로딩(LAZY)으로 설정해야 한다.
  • 연관된 엔티티를 함께 DB에서 조회해야 하면, fetch join 또는 엔티티 그래프 기능을 사용한다.
  • @XToOne(OneToOne, ManyToOne) 관계는 기본이 즉시 로딩이므로 직접 지연로디으로 설정해야한다.

 

* Item 엔티티 - 상품 정보

Item.java

 

@Inheritance(strategy=)

JPA에서 엔티티 상속 구조를 DB에 어떻게 저장할지 결정하는 상속 전략 방식이다.

 

InheritanceType.SINGLE_TABLE)

상속된 모든 엔티티를 하나의 테이블에 저장하는 방식이다.

단일 테이블 전략은 모든 상속된 엔티티가 하나의 테이블의 저장되므로 조인이 필요 없고 성능이 빠르지만, 비어있는 컬럼이 많이 생길 수 있다.

만약 각 상품(item)들마다 별도의 테이블을 생성한 조인 전략을 사용했다면, 테이블 수가 늘어나고 복잡한 조인 연산이 자주 발생하기에 단일 테이블 전략을 사용한 것이다.

 

@DiscriminatorColumn(name="dtype")

상속 구조에서 엔티티 타입을 구분하는 컬럼을 지정하는 어노테이션이다.

dtype이라는 컬럼이 테이블에 추가되며, 이 컬럼을 통해 어떤 엔티티가 저장되었는지 구분한다.

예를 들어, Book, Movie, Album 등과 같은 하위 아이템들이 dtype 값으로 구분된다.

 

* Album, Book, Movie 엔티티

Album.java
Book.java
Movie.java

 

@DiscriminatorValue

상속구조에서 상위 엔티티 테이블(단일 테이블)에 구체적인 엔티티를 구분할 때 사용되는 값을 지정한다.

 

* Delivery 엔티티 - 배송 정보

Delivery.java

 

* DeliveryStatus 엔티티 - 배송 상태 정보

DeliveryStatus.java

 

* Category 엔티티 - 카테고리 정보

Category.java

 

@JoinTable

다대다 관계를 풀기 위해 중간 테이블을 설정한다.

중간 테이블은 category_item이라는 테이블로, 두 엔티티 간의 관계를 관리한다.

  • joincolumns : 현재 엔티티(Category)의 외래키(category_id)를 지정
  • inverseJoinColumns : 상태방 엔티티(Item)의 외래키(item_id)를 지정

JoinColumn(name="parent_id")

DB에서 부모 카테고리의 외래키(parent_id)와 연결된다.

 

* DB 확인

DB

 

테이블이 설계한 대로 잘 생성되었다.

끝.

 

728x90
LIST

댓글