본문 바로가기

SPRING/Spring 활용

[스프링부트| 스프링부트와 JPA 활용 1 | 웹 애플리케이션 개발 | 도메인 분석 설계] 엔티티 클래스 개발

@Entity // 이 클래스를 데이터베이스의 엔티티로 선언
@Getter // Lombok 라이브러리를 사용하여 모든 필드의 getter 메서드 자동 생성
@Setter // Lombok 라이브러리를 사용하여 모든 필드의 setter 메서드 자동 생성
public class Member { // 회원을 나타내는 클래스

    @Id // 이 필드가 테이블의 기본 키임을 선언
    @GeneratedValue // 기본 키 값이 데이터베이스에 의해 자동으로 생성되어야 함을 선언
    @Column(name = "member_id") // 데이터베이스의 컬럼 이름을 "member_id"로 지정
    private Long id; // 회원 식별자

    private String name; // 회원의 이름

    @Embedded // 이 필드가 내장 타입임을 선언, Address 클래스의 필드들이 이 엔티티의 테이블 내에서 컬럼으로 포함됨
    private Address address; // 회원의 주소

    @OneToMany(mappedBy = "member") // 이 회원과 연관된 주문들의 리스트, "member" 필드에 의해 매핑됨
    private List<Order> orders = new ArrayList<>(); // 회원의 주문 목록, 기본적으로 빈 리스트로 초기화

}

@GeneratedValue

@GeneratedValue는 Java Persistence API(JPA)에서 엔티티의 기본 키(primary key) 값이 어떻게 자동으로 생성될지를 명시하는 어노테이션입니다. 이 어노테이션은 주로 @Id 어노테이션과 함께 사용되어, 해당 엔티티의 식별자가 데이터베이스에 의해 자동으로 할당되도록 설정합니다.

사용법

@GeneratedValue 어노테이션은 다음과 같은 속성을 가질 수 있습니다:

  • strategy: 식별자 생성 전략을 지정합니다. 사용할 수 있는 전략은 GenerationType 열거형에 정의된 값 중 하나를 사용합니다.
  • generator: 식별자 생성기를 지정합니다. 이 속성은 주로 커스텀 생성기를 사용할 때 참조하는 이름입니다.

전략(Strategy)

GenerationType 열거형에서는 다음과 같은 주요 식별자 생성 전략을 제공합니다:

  1. AUTO (기본값): 특정 데이터베이스에 맞게 JPA 구현체가 자동으로 적절한 전략을 선택합니다.
  2. IDENTITY: 데이터베이스의 IDENTITY 컬럼을 사용하여 기본 키를 생성합니다. 이 전략은 데이터베이스가 새로운 레코드를 삽입할 때 자동으로 증가하는 숫자 값을 생성합니다. MySQL과 Microsoft SQL Server에서 사용됩니다.
  3. SEQUENCE: 데이터베이스의 시퀀스를 사용하여 기본 키를 생성합니다. 이 전략은 @SequenceGenerator 어노테이션과 함께 사용하여 시퀀스 이름과 함께 다른 매개변수를 명시할 수 있습니다. Oracle, PostgreSQL, DB2, H2 데이터베이스 등에서 사용됩니다.
  4. TABLE: 키 생성을 위해 별도의 테이블을 사용합니다. 이 테이블은 사용 가능한 키 값을 저장하고, 각 삽입 작업에 대해 키 값을 증가시킵니다. 이 전략은 특정 데이터베이스 기능에 의존하지 않기 때문에 데이터베이스 간 이식성이 뛰어납니다.
@Entity // 이 클래스를 데이터베이스 테이블에 매핑할 엔티티로 선언
@Table(name = "orders") // 이 엔티티가 매핑될 데이터베이스 테이블의 이름을 'orders'로 지정
@Getter // Lombok 라이브러리를 사용하여 모든 필드의 getter 메서드 자동 생성
@Setter // Lombok 라이브러리를 사용하여 모든 필드의 setter 메서드 자동 생성
public class Order { // 주문을 나타내는 클래스

    @Id @GeneratedValue // 이 필드를 테이블의 기본 키로 설정하고, 값은 데이터베이스가 자동으로 생성
    @Column(name = "order_id") // 데이터베이스의 컬럼 이름을 "order_id"로 지정
    private Long id; // 주문의 고유 식별자

    @ManyToOne // 다대일 관계를 나타내며, 여러 주문이 하나의 회원에게 속할 수 있음
    @JoinColumn(name = "member_id") // 외래 키로 'member_id'를 사용
    private Member member; // 이 주문을 한 회원

    @OneToMany(mappedBy = "order") // 일대다 관계를 나타내며, 하나의 주문이 여러 주문 항목을 포함할 수 있음
    private List<OrderItem> orderItems = new ArrayList<>(); // 주문 항목 목록

    @OneToOne // 일대일 관계를 나타내며, 하나의 주문이 하나의 배송 정보를 가짐
    @JoinColumn(name = "delivery_id") // 외래 키로 'delivery_id'를 사용
    private Delivery delivery; // 이 주문의 배송 정보

    private LocalDateTime orderDate; // 주문 날짜와 시간

    @Enumerated(EnumType.STRING) // 이 필드를 열거형 타입으로 지정하며, 데이터베이스에 문자열로 저장
    private OrderStatus status; // 주문 상태, 열거형 [ORDER, CANCEL] 값 중 하나를 가짐

}
package jpabook.jpashop.domain;

public enum OrderStatus {
    ORDER, CANCEL
}
@Entity // 이 클래스를 데이터베이스 테이블에 매핑할 엔티티로 선언
@Getter // Lombok 라이브러리를 사용하여 모든 필드의 getter 메서드 자동 생성
@Setter // Lombok 라이브러리를 사용하여 모든 필드의 setter 메서드 자동 생성
public class OrderItem { // 주문 항목을 나타내는 클래스

    @Id @GeneratedValue // 이 필드를 테이블의 기본 키로 설정하고, 값은 데이터베이스가 자동으로 생성
    @Column(name = "order_item_id") // 데이터베이스의 컬럼 이름을 "order_item_id"로 지정
    private Long id; // 주문 항목의 고유 식별자

    @ManyToOne // 다대일 관계를 나타내며, 여러 주문 항목이 하나의 아이템에 속할 수 있음
    @JoinColumn(name = "item_id") // 외래 키로 'item_id'를 사용
    private Item item; // 이 주문 항목에 해당하는 상품

    @ManyToOne // 다대일 관계를 나타내며, 여러 주문 항목이 하나의 주문에 속할 수 있음
    @JoinColumn(name = "order_id") // 외래 키로 'order_id'를 사용
    private Order order; // 이 주문 항목이 속한 주문

    private int orderPrice; // 주문 가격
    private int count; // 주문 수량

}
@Entity // 이 클래스를 데이터베이스 테이블에 매핑할 엔티티로 선언
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) // 단일 테이블 상속 전략을 사용하여 모든 자식 클래스를 하나의 테이블에 저장
@DiscriminatorColumn(name = "dtype") // 상속된 엔티티를 구분할 컬럼 이름을 "dtype"로 지정
@Getter // Lombok 라이브러리를 사용하여 모든 필드의 getter 메서드 자동 생성
@Setter // Lombok 라이브러리를 사용하여 모든 필드의 setter 메서드 자동 생성
public abstract class Item { // 추상 클래스로 선언, 직접 인스턴스화할 수 없으며 상속을 통해 구체적인 아이템 클래스를 생성

    @Id @GeneratedValue // 이 필드를 테이블의 기본 키로 설정하고, 값은 데이터베이스가 자동으로 생성
    @Column(name = "item_id") // 데이터베이스의 컬럼 이름을 "item_id"로 지정
    private Long id; // 상품의 고유 식별자

    private String name; // 상품 이름
    private int price; // 상품 가격
    private int stockQuantity; // 상품 재고 수량

    @ManyToMany(mappedBy = "items") // 다대다 관계를 나타내며, 여러 상품이 여러 카테고리에 속할 수 있음
    private List<Category> categories = new ArrayList<>(); // 이 상품이 속한 카테고리 목록
}

@Entity // 이 클래스를 데이터베이스 테이블에 매핑할 엔티티로 선언
@Getter // Lombok 라이브러리를 사용하여 모든 필드의 getter 메서드 자동 생성
@Setter // Lombok 라이브러리를 사용하여 모든 필드의 setter 메서드 자동 생성
public class Category { // 카테고리를 나타내는 클래스

    @Id @GeneratedValue // 이 필드를 테이블의 기본 키로 설정하고, 값은 데이터베이스가 자동으로 생성
    @Column(name = "category_id") // 데이터베이스의 컬럼 이름을 "category_id"로 지정
    private Long id; // 카테고리의 고유 식별자

    private String name; // 카테고리 이름

    @ManyToMany // 다대다 관계를 나타내며, 하나의 카테고리가 여러 상품을 포함할 수 있고, 하나의 상품이 여러 카테고리에 속할 수 있음
    @JoinTable(name = "category_item", // 다대다 관계를 매핑하는 연결 테이블을 지정
            joinColumns = @JoinColumn(name = "category_id"), // 현재 엔티티를 연결 테이블에 매핑하는 컬럼
            inverseJoinColumns = @JoinColumn(name = "item_id")) // 연결된 다른 엔티티를 연결 테이블에 매핑하는 컬럼
    private List<Item> items = new ArrayList<>(); // 이 카테고리에 속한 상품 목록

    @ManyToOne // 다대일 관계를 나타내며, 하위 카테고리가 하나의 상위 카테고리에 속할 수 있음
    @JoinColumn(name = "parent_id") // 상위 카테고리와 연결되는 외래 키 컬럼
    private Category parent; // 이 카테고리의 상위 카테고리

    @OneToMany(mappedBy = "parent") // 일대다 관계를 나타내며, 하나의 카테고리가 여러 하위 카테고리를 포함할 수 있음
    private List<Category> child = new ArrayList<>(); // 이 카테고리의 하위 카테고리 목록


}

테이블, 컬럼명 생성 전략
스프링 부트에서 하이버네이트 기본 매핑 전략을 변경해서 실제 테이블 필드명은 다름

https://docs.spring.io/spring-boot/docs/2.1.3.RELEASE/reference/htmlsingle/#howto-configure-hibernate-naming-strategy

http://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#naming

CascadeType.ALL

CascadeType.ALL은 해당 엔티티에 대해 수행되는 모든 생명주기 변경(생성, 업데이트, 삭제 등)이 관련 엔티티에도 적용되도록 지정합니다. 구체적으로는 다음과 같은 CascadeType들을 모두 포함합니다:

  • PERSIST: 엔티티를 영속화할 때(저장할 때), 연관된 엔티티도 함께 영속화됩니다.
  • REMOVE: 엔티티를 삭제할 때, 연관된 엔티티도 함께 삭제됩니다.
  • MERGE: 엔티티 상태를 병합할 때, 연관된 엔티티의 상태도 함께 병합됩니다.
  • REFRESH: 엔티티를 새로 고칠 때, 연관된 엔티티도 함께 새로 고쳐집니다.
  • DETACH: 엔티티가 영속성 컨텍스트에서 분리될 때, 연관된 엔티티도 함께 분리됩니다.

사용 예

예를 들어, Order 엔티티와 OrderItem 엔티티가 있고, Order 엔티티에 여러 OrderItem 엔티티가 연관되어 있다고 가정해 봅시다. 여기서 Order 엔티티에 cascade = CascadeType.ALL을 설정하면, Order 엔티티를 저장할 때 연관된 모든 OrderItem 엔티티도 자동으로 저장됩니다. 또한, Order 엔티티를 삭제할 경우 연관된 모든 OrderItem 엔티티도 함께 삭제됩니다.