[24.09.15] TIL

yy·2024년 9월 15일

개발일지

목록 보기
105/122

java, jpa 공부중

상속관계 매핑

  • 객체는 상속관계 O, RDB 상속관계X (슈퍼 타입 서브타입 관계라는 모델링 기법이 객체 상속과 유사)
  • 상속 관계 매핑 : 객체의 상속 구조 ~(매핑)~ DB의 슈퍼 타입 서브타입 관계
  • 상속관계매핑은 물리모델로 바꾸는 어떤 방법이든 지원을 해줌

논리->물리 모델 구체화 방법

  • 조인전략 JOINED (공통속성은 하나의 테이블로 묶고, 개별속성은 각 테이블에 넣되, 조인해서 사용하는 방법)
  • 단일테이블전략 SINGLE_TABLE (한 테이블에 속성들을 다 넣는 방법)
  • 구현 클래스마다 테이블 전략 TABLE_PER_CLASS (공통속성으로 묶지않고 각각의 테이블이 속성을 다 갖고 있는 방법)
package jpabook.jpashop.domain;

import jakarta.persistence.*;

@Entity
public class Item {
    @Id
    @GeneratedValue
    @Column(name = "ITEM_ID")
    private Long id;

    private String name;
    private int price;
}
package jpabook.jpashop.domain;

import jakarta.persistence.Entity;
import jakarta.persistence.Table;

@Entity
public class Album extends Item{
    private String artist;
}
package jpabook.jpashop.domain;

import jakarta.persistence.Entity;
import jakarta.persistence.Table;

@Entity
public class Book extends Item{
    private String author;
    private String isbn;
}
package jpabook.jpashop.domain;

import jakarta.persistence.Entity;
import jakarta.persistence.Table;

@Entity
public class Movie extends Item{
    private String director;
    private String actor;
}

위와 같이 item을 상속받는 Album, Book, Movie. jpa의 기본전략이 단일테이블전략 SINGLE_TABLE 을 사용한다.

Hibernate: 
    create table ITEM (
        price integer not null,
        ITEM_ID bigint not null,
        DTYPE varchar(31) not null,
        actor varchar(255),
        artist varchar(255),
        author varchar(255),
        director varchar(255),
        isbn varchar(255),
        name varchar(255),
        primary key (ITEM_ID)
    )


전략 변경 방법

  • 부모클래스에 어노테이션을 붙여서 전략을 변경할 수 있음.

1. 조인 전략

@Entity
@Inheritance( strategy = InheritanceType.JOINED) //조인 전략
@DiscriminatorColumn // DTYPE (name을 안적으면 기본 DTYPE 컬럼이 생성됨. 들어가는 값은 자식클래스의 엔티티명)
public class Item {
	...
}
// @DiscriminatorColumn 에 이어서 자식클래스
@Entity
@DiscriminatorColumn("A") //자식클래스의 엔티티명이 아닌 별도 지정해주고싶으면 이 어노테이션 넣으면 됨.
public class Album extends Item{
    private String artist;
}
  • 각 테이블 create 후 alter add 쿼리가 실행되어 외래 키 설정을 해줌. (일부 채취)

    값을 넣어보면
Movie movie = new Movie();
movie.setActor("크리스틴 스튜어트");
movie.setDirector("로즈 글래스");
movie.setName("러브 라이즈 블리딩");
movie.setPrice(10000);
em.persist(movie);
tx.commit();


조회하면 join처리해서 가져옴.

2. 단일 테이블 전략

@Entity
@Inheritance( strategy = InheritanceType.SINGLE_TABLE) // 여기만 바꾸면됨. 
// @DiscriminatorColumn 단일 테이블 전략에서는 안적어도 DTYPE이 자동으로 생성됨. 
public class Item {
	...
}


3. 구현 클래스마다 테이블 전략

@Entity
@Inheritance( strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Item {
	...
}

추상클래스로 만들면 item테이블은 안만들어지고 나머지 자식클래스들만 만들어짐.

insert할 때는 각 테이블에만 쿼리가 날라가고, 조회할 때도 각 테이블에서만 조회가 된다. 조회할 때도 각 해당되는 객체를 통해서 조회하면 문제가 되지않지만, 부모클래스(item)에서 조회를 하려고 하면 온 갖 union쿼리 실행되면서 복잡해진다.



각 전략 장단점

조인전략

  • 장점

    • 테이블 정규화
    • 외래 키 참조 무결성 제약조건 활용가능
    • 저장공간 효율화
  • 단점

    • 조회 시 조인을 많이 사용. (성능 저하)
    • 조회 쿼리가 복잡
    • 데이터 저장 시 insert 쿼리 2번 호출

단일 테이블 전략

  • 장점

    • 조인이 필요X -> 일반적으로 조회 성능 빠름
    • 조회 쿼리 단순
  • 단점

    • 자식 엔티티가 매핑한 컬럼은 모두 null허용
    • 단일 테이블에 모든 걸 저장 -> 테이블 커질 수 있음. 상황에 따라 조회 성능 저하 가능성 있음.

구현 테이블마다 테이블 전략 (데이터베이스 설계자, ORM 전문가 둘 다 추천X)

  • 장점

    • 서브 타입을 명확하게 구분해서 처리할 때 효과적
    • not null 제약조건 사용 가능
  • 단점

    • 여러 자식 테이블을 함께 조회할 때 성능이 느림(union)
    • 자식 테이블을 통하해서 쿼리하기 어려움


@MappedSupercalss

  • 공통 매핑 정보가 필요할 때 사용(id, name)

  • 테이블 간 연관관계가 있는건 아니고 그냥 id, name같은 계속 반복되는걸 기본엔티티를 가지고 상속받아서 쓰면 덜 피곤하니까 그럴려고 만든거임. 공통 속성모아서 상속해서 쓰려고 만든거.

  • 상속관계 매핑X

  • 엔티티X, 테이블과 매핑X

  • 부모 클래스를 상속 받는 자식 클래스에 매핑 정보만 제공

  • 조회, 검색 불가(em.find(BaseEntity) 불가)

  • 직접 생성해서 사용할 일이 없으므로 추상 클래스 권장

  • 테이블과 관계 없고,

  • 단순히 엔티티가 공통으로 사용하는 매핑 정보를 모으는 역할

  • 주로 등록일, 수정일, 등록자, 수정자 같은 전체 엔티티에서 공통 으로 적용하는 정보를 모을 때 사용

  • 참고: @Entity 클래스는 엔티티나 @MappedSuperclass로 지 정한 클래스만 상속 가능

package jpabook.jpashop.domain;

import jakarta.persistence.MappedSuperclass;

@MappedSuperclass
public abstract class BaseEntity {

    private String createdBy; //공통 속성
}
public class Item extends BaseEntity{
...
}


상속 관계 매핑 코드
package jpabook.jpashop.domain;

import jakarta.persistence.*;

import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "MEMBER")
public class Member extends BaseEntity{
  @Id @GeneratedValue
  @Column(name = "MEMBER_ID")
  private Long id;
  private String name;
  private String city;
  private String street;
  private String zipcode;

  @OneToMany(mappedBy = "member")
  private List<Order> order = new ArrayList<>();

}
package jpabook.jpashop.domain;

import jakarta.persistence.MappedSuperclass;

import java.time.LocalDateTime;

@MappedSuperclass
public abstract class BaseEntity {

  private LocalDateTime createdDate;
  private LocalDateTime updatedDate;

  public LocalDateTime getCreatedDate() {
      return createdDate;
  }

  public void setCreatedDate(LocalDateTime createdDate) {
      this.createdDate = createdDate;
  }

  public LocalDateTime getUpdatedDate() {
      return updatedDate;
  }

  public void setUpdatedDate(LocalDateTime updatedDate) {
      this.updatedDate = updatedDate;
  }
}
package jpabook.jpashop.domain;

import jakarta.persistence.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "ORDERS")
public class Order extends BaseEntity{
  @Id
  @GeneratedValue
  @Column(name = "ORDER_ID")
  private Long id;

  @ManyToOne
  @JoinColumn(name = "MEMBER_ID")
  private Member member;

  @OneToMany(mappedBy = "order")
  private List<OrderItem> orderItems = new ArrayList<>();

  private LocalDateTime orderDate;

  @Enumerated(EnumType.STRING)
  private OrderStatus status;

  @OneToOne
  @JoinColumn(name = "DELIVERY_ID")
  private Delivery delivery;
}
package jpabook.jpashop.domain;

import jakarta.persistence.*;

@Entity
@Table(name = "ORDER_ITEM")
public class OrderItem extends BaseEntity{

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

  @ManyToOne
  @JoinColumn(name = "ITEM_ID")
  private Item item;

  @ManyToOne
  @JoinColumn(name = "ORDER_ID")
  private Order order;

  private int orderPrice;
  private int count;
}
package jpabook.jpashop.domain;

public enum OrderStatus {
  PENDING, ORDER, CANCEL
}
package jpabook.jpashop.domain;

import jakarta.persistence.*;

@Entity
@Table(name = "DELIVERY")
public class Delivery extends BaseEntity{
  @Id
  @GeneratedValue
  @Column(name = "DELIVERY_ID")
  private Long id;

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

  private String city;
  private  String zipcode;

  @Enumerated
  private DeliveryStatus status;

}
package jpabook.jpashop.domain;

public enum DeliveryStatus {
  PENDING, DELIVERING, COMPLETE
}
package jpabook.jpashop.domain;

import jakarta.persistence.*;

import java.util.ArrayList;
import java.util.List;

@Entity
@Inheritance( strategy = InheritanceType.SINGLE_TABLE)
public abstract class Item extends BaseEntity{
  @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<>();
}
package jpabook.jpashop.domain;

import jakarta.persistence.DiscriminatorColumn;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;

@Entity
public class Album extends Item{
  private String artist;
  private String etc;

  public String getArtist() {
      return artist;
  }

  public void setArtist(String artist) {
      this.artist = artist;
  }

  public String getEtc() {
      return etc;
  }

  public void setEtc(String etc) {
      this.etc = etc;
  }
}
package jpabook.jpashop.domain;

import jakarta.persistence.Entity;
import jakarta.persistence.Table;

@Entity
public class Movie extends Item{
  private String director;
  private String actor;

  public String getDirector() {
      return director;
  }

  public void setDirector(String director) {
      this.director = director;
  }

  public String getActor() {
      return actor;
  }

  public void setActor(String actor) {
      this.actor = actor;
  }
}
package jpabook.jpashop.domain;

import jakarta.persistence.Entity;
import jakarta.persistence.Table;

@Entity
public class Book extends Item{
  private String author;
  private String isbn;

  public String getAuthor() {
      return author;
  }

  public void setAuthor(String author) {
      this.author = author;
  }

  public String getIsbn() {
      return isbn;
  }

  public void setIsbn(String isbn) {
      this.isbn = isbn;
  }
}
profile
시간이 걸릴 뿐 내가 못할 건 없다.

0개의 댓글