[SpringBoot] 스프링 부트와 JPA 활용1 - 엔티티 클래스 개발

히똔 2022. 7. 23. 15:52
728x90
반응형

참고 강의 : (인프런) 실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-JPA-%ED%99%9C%EC%9A%A9-1/dashboard

 

실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 - 인프런 | 강의

실무에 가까운 예제로, 스프링 부트와 JPA를 활용해서 웹 애플리케이션을 설계하고 개발합니다. 이 과정을 통해 스프링 부트와 JPA를 실무에서 어떻게 활용해야 하는지 이해할 수 있습니다., - 강

www.inflearn.com

강의를 직접 듣고 개인적으로 정리한 내용입니다.

 

엔티티 클래스 개발


  • 실무에서는 Getter을 모두 열어두는 것이 편하다. 호출하는 것 만으로는 어떤 일이 발생하지 않는다.
  • 하지만 Setter는 호출하면 테이터가 변한다. 때문에 Setter는 필요한 곳에만 적절히 지정해주어야한다.

 

Member.java

package jpabook.jpashop.domain;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Getter @Setter // Lombok 쓰니까 어노테이션으로 자동생성됨
public class Member {

    @Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;

    private String name;

    @Embedded
    private Address address;

    @OneToMany //Member - Order 일대다 (하나의 멤버가 여러개의 주문을 할 수 있다.)
    private List<Order> orders = new ArrayList<>();
}
  • @Column(name=”member_id”) : 엔티티 식별자는 id이지만 pk 컬럼면은 member_id이다.
  • @OneToMany : Member를 기준으로 봤을때 Member - Order은 일대다 관계이다. (하나의 멤버가 여러개를 주문 할 수 있다.)

 

Order.java

package jpabook.jpashop.domain;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;

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

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

    @ManyToOne // Order-Member : 다대일
    @JoinColumn("member_id") // 포른키가 member_id로 설정됨
    private Member member;

}
  • @Table(name=”orders”) : 엔티티 식별자는 Order이지만 테이블명은 orders이다.
  • @ManyToOne : Order를 기준으로 봤을때 Order-Member는 다대일 관계
  • 포른키가 생성될때 연관관계의 주인장을 설정해줘야한다.⇒ 주인이 아닌 Member 속 order에 설정을 해주어야한다
    • @OneToMany(mappedBy = “member”) : order내의 member에게서 받아온다.⇒ 나는 매핑 시켜주는 애가 아니고, 난 매핑값 받아오는 거울일 뿐이야.
    • ⇒ 얘가 변경된다고 해서 주인장의 데이터가 변경되지 않는다.
Member.java @OneToMany(mappedBy = "member") //order내의 member에게서 받아온다. 
private List<Order> orders = new ArrayList<>();
  • ⇒ Order내의 member 가 주인이다.

 

Item.java

추상클래스로 만들고, 상속받는 아이들한테서 구현체를 따로 만들기

package jpabook.jpashop.domain;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="dtype")
@Getter @Setter
public abstract class Item { //추상클래스로 만들기 (구현체 따로 만들기 => 상속관계 매핑해야돼서)
    @Id
    @GeneratedValue
    @Column(name = "item_id")
    private Long id;

    private String name;
    private int price;
    private int stockQuantity;
}
  • 상속관계 만들시 @Inheritance 추가
    • SINGLE_TABLE : 한 테이블에 다 때려박기
    • JOINED :

 

Delivery.java

package jpabook.jpashop.domain;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;

@Entity
@Getter
@Setter
public class Delivery {
    @Id @GeneratedValue
    @Column(name="delivery_id")
    private Long id;

    @OneToOne(mappedBy = "delivery")
    private Order order;

    @Embedded
    private Address address;

    @Enumerated(EnumType.STRING) //ordinary : 숫자로 들어감 => String 으로 해줘야함.
    private DeliveryStatus status; //Ready, Comp
}
  • @Enumerated
    • EnumType.ORDINARY : 기본 설정, 숫자로 들어감.
    • ⇒ 문제점: 지정된 것 외에 다른 것이 들어가면 에러가 난다
    • EnumType.STRING : 다른것이 들어가더라도 String이기 때문에 괜찮다.

 

Category - Item 다대다 관계 처리

catergory_item 엔티티를 따로 두고 진행

 

Category.java

package jpabook.jpashop.domain;

import jpabook.jpashop.domain.item.Item;
import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Getter @Setter
public class Category {
    @Id @GeneratedValue
    @Column(name="catergory_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<>();
}

 

Item.java

package jpabook.jpashop.domain.item;

import jpabook.jpashop.domain.Category;
import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="dtype")
@Getter @Setter
public abstract class Item { //추상클래스로 만들기 (구현체 따로 만들기 => 상속관계 매핑해야돼서)
    @Id
    @GeneratedValue
    @Column(name = "item_id")
    private Long id;

    private String name;
    private int price;
    private int stockQuantity;

    @ManyToMany(mappedBy = "items")
    private List<Category> categories=new ArrayList<>();
}
  • 그런데 실무에서는 @ManytoMany 사용하면 안된다.
    • 운영하기 어려움
    • 컬럼 추가 불가능
  • 일대다, 다대일 로 풀어서 사용하기! (CategoryItem 중간 엔티티 생성해서 하기)

 

Address.java

package jpabook.jpashop.domain;

import lombok.Getter;

import javax.persistence.Embeddable;

@Embeddable //jpa 내장 타입
@Getter
public class Address {
    private String city;
    private String street;
    private String zipcode;

    protected Address(){
        // 기본 생성자 만들어줘야 에러가 안남.
        // Address를 함부러 건들이면 안된다.
    }

    //@ Setter 없으니까 초기에 set하는 거 넣어주기 : 생성할때만 세팅됨!!
    public Address(String city, String street, String zipcode) {
        this.city = city;
        this.street = street;
        this.zipcode = zipcode;
    }
}
  • Address에 @Setter를 없애서 함부러 변경 불가토록 코딩
  • 초기에 set 해주는 코드 삽입
  • protected 로 생성자 생성하여 함부러 건들이지 못하도록 함

 

엔티티 설계시 주의점


  1. 엔티티에는 가급석 setter 사용 말자
  2. 모든 연관관계는 지연(lazy)로딩으로 설정 (즉시 로딩 X)
    1. 즉시(eager) 로 하면 해당 엔티티와 관련된 데이터 모두 다 끌어와서 효율성 측면에서 좋지 않다
    2. 실시간으로 데이터를 가져올 수 있는 fetch join으로 최적화 하면된다.
    3. XtoMany는 디폴트가 lazy이기 때문에 그냥 두면 된다.
    4. XtoOne은 디폴트가 eager여서 모두 바꿔야한다
      @ManyToOne(fetch = FetchType.LAZY)
  3. Cascade
    1. 하나만 persist 해줘도 다른 애들로 전파돼서 다른애들도 같이 persist 됨
@OneToMany(mappedBy = "order",cascade = CascadeType.ALL) //orderitem 내 order가 주인ㄴ장
private List<OrderItem> orderItems = new ArrayList<>();

@OneToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
@JoinColumn(name="delivery_id")
private Delivery delivery;
728x90
반응형