java/jpa

[JPA] DDL-AUTO 테이블 자동 생성 전략 - SQL Column 매칭

danuri 2021. 6. 10. 20:03

spring.jpa.hibernate.ddl-auto 옵션에서 create 혹은 create-drop 옵션을 사용하면 애플리케이션 실행시 DB 테이블들을 모두 Drop 하고 @Entity로 등록한 객체들을 DB 테이블로 새롭게 Create한다.

spring:
  jpa:
    hibernate:
      ddl-auto: create

 

다음 엔티티를 DB 테이블로 등록한다고 하자.

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

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "order_id")
    private Long id;
    
    private int price;
    private String name;
    private LocalDateTime orderDate;
    
    @Enumerated(EnumType.STRING)
    private OrderStatus status;

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

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

 

애플리케이션 실행시 발생 쿼리는 다음과 같다.

create table orders (
       order_id bigint not null auto_increment,
       
       price integer not null,
       name varchar(255),
       order_date datetime(6),
       
       status varchar(255),
       
       member_id bigint,
       
       primary key (order_id)
    )

alter table orders 
       add constraint FKpktxwhj3x9m4gth5ff6bkqgeb 
       foreign key (member_id) 
       references member (member_id);

하나씩 분석해보자.

 

 

<테이블 이름>

@Table(name = "orders")
public class Order

-> 쿼리

create table orders

테이블의 이름은 @Table(name ="xxx")에 설정한 이름으로 등록된다.

 

<기본키, PK>

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "order_id")
private Long id;

-> 쿼리

order_id bigint not null auto_increment
...
primary key (order_id)

 

Column의 이름은 @Column(name="xxx")에 설정한 이름으로 등록된다.

Long 타입은 bigint로 등록된다.

PK는 기본적으로 not null 옵션이 추가된다.

@GeneratedValue로 인해 auto_increment 옵션이 추가된다.

@Id로 기본키 설정을 했기 때문에 primary key(order_id)가 자동 생성된다.

 

<일반 컬럼>

private int price;
private String name;
private LocalDateTime orderDate;

-> 쿼리

price integer not null,
name varchar(255),
order_date datetime(6),

int 타입은 integer로 등록된다.

-> 그리고 int는 Long, Integer와 같은 래퍼 클래스와 다르게 Null을 담을 수 없기 때문에 not null 옵션을 추가한다.

String 타입은 varchar(255)로 등록된다.

LocalDateTime 타입은 datetime(6)으로 등록된다.

 

+) 자바 코드를 보면 각 필드에 @Column 애노테이션을 붙이지 않았다. 앞서 PK처럼 @Column(name="xxx")로 직접 Column 이름을 정할 수 있지만 생략할 수도 있다.

생략했을 때는 일정 규칙에 따라 Column 이름이 생성된다. 기본적으로 필드의 이름을 그대로 Column 이름으로 사용하지만 orderDate와 같은 카멜케이스의 경우 order_date처럼 스네이크 케이스로 설정된다.

 

<Enum 타입>

@Enumerated(EnumType.STRING)
private OrderStatus status;

-> 쿼리

status varchar(255)

Enum 타입은 @Enumerated()에 등록한 EnumType 옵션에 따라서 설정된다.

-> 여기서는 STRING 타입을 사용했기 때문에 varchar(255)가 설정된다.

 

<연관관계>

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

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

-> 쿼리

member_id bigint

...

alter table orders 
       add constraint FKpktxwhj3x9m4gth5ff6bkqgeb 
       foreign key (member_id) 
       references member (member_id);

@ManytoOne 다대일 연관관계의 경우 '다' 쪽인 Order 클래스가 외래키를 갖고 있기 때문에 '일'쪽의 기본키 타입으로 Column을 생성한다.

-> Member 클래스의 기본키가 Long 타입이라 한다면 bigint로 등록되는 것이다.

member_id는 결국 외래키이기 때문에 create 쿼리가 끝나면 alter 쿼리로 외래키 자격을 부여하는 것이다.

 

@OneToMany 일대다 연관관계의 경우 '일' 쪽인 Order 클래스는 외래키를 갖고 있지 않기 때문에 따로 Column을 생성하지 않는다.

 

이 밖에도 JPA는 다양한 타입들과 상황에 대해 적절하게 쿼리를 매칭시켜준다.

ddl-auto 옵션을 사용해서 직접 테스트 해보는 것이 좋다.