3 minute read

Updated:

👩🏻‍💻 SQL Scripts를 사용하여 데이터를 초기화한 과정을 기록한다.

DB 테이블과 데이터를 초기에 생성해야하는 프로젝트를 만들게 되었다. 로컬과 테스트 환경에서만 구동할 것이므로 DB는 in-memory인 H2를 사용하기로 했다. Spring Boot 환경에서 DB를 초기화하는 방법은 JPA, Hibernate, SQL Script 등 사용하는 기술 스택에 따라 다양했는데, 내 프로젝트는 hibernate를 사용하고 있어 DDL 생성 기능을 사용해 스키마를 생성했다.

hibernate로 h2 Database 초기화 방법

1. Spring Data JPA와 H2 의존성을 추가한다.

//생략

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.h2database:h2'

//생략

2. application.properties 또는 application.yml 파일에 h2 DB에 관련된 설정을 추가한다.

    spring:
      datasource:
        url: jdbc:h2:mem:test
        username: sa
        password:
        driver-class-name: org.h2.Driver
      h2:
        console:
          enabled: true
          path: /h2-console
      jpa:
        hibernate:
          ddl-auto: create
        properties:
          hibernate:
            format_sql: true
            show_sql: true
        defer:
          datasource:
            initialization: true

application.yml 파일의 주요 속성은 아래와 같다.

  • spring.datasource.url
    • H2 Database는 url을 기준으로 모드를 적용할 수 있다.
    • In-memory 모드 : jdbc:h2:mem:<databaseName>
    • mbedded (로컬) 모드 : jdbc:h2:~/test 또는 jdbc:h2:[file:][<path>]<databaseName>
    • mbedded 모드는 WAS 구동 시 DB 데이터를 로컬에 저장하는 방식이다. In-memory와 달리 비휘발성이므로 데이터 손실을 방지할 때 사용할 수 있다. 내 프로젝트에서는 In-memory 방식을 사용했다.
  • username, password
    • 기본적으로 Spring Boot는 username:sa와 빈 비밀번호를 사용하여 메모리 내 저장소에 연결한다.
  • h2.console.enabled: true
    • H2 데이터베이스에는 GUI 콘솔이 내장되어 있다. 기본적으로 H2 콘솔은 Spring에서 활성화되지 않으므로 해당 속성을 추가해야 접속이 가능하다.
    • H2 GUI 콘솔 접속 url : http://localhost:8080/h2-console
  • jpa.hibernate.ddl-auto
    • DDL 쿼리의 수행 방식을 지정한다.
      • create: 기존 테이블을 삭제하고 다시 생성한다.
      • create-drop: create와 동일하나, 종료 시점에 테이블을 제거한다.
      • update: 변경부분만 반영한다.
      • validate: 엔터티와 테이블이 정상 매핑된 것인지만 확인한다.
      • none: 엔터티를 통한 자동생성을 사용하지 않고, schema.sql 파일이 있는경우 해당 파일을 사용한다.
  • format_sql: true / show_sql: true
    • DB에 날리는 모든 쿼리를 포맷팅해서 보기 위해 추가했다.
  • defer.datasource.initialization
    • 기본적으로 Hibernate 초기화 전에 data.sql 스크립트가 실행된다. 따라서 Hibernate에 의해 생성된 스키마를 기반으로 스크립트를 실행하려면 해당 속성을 추가해야한다.
    • 공식 문서에 따르면 DB 초기화 기술을 혼합하는 것은 권장하지 않는 방식이다. 현재 버전은 Hibernate와 SQL Scripts를 혼합한 방식이다.

3. entity 클래스를 작성한다.

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Item {
  @Id
  @Column(name = "item_id")
  private Long id;

  private String name;

  private int price;

  private int stockQuantity;

  @Builder
  public Item(Long id, String name, int price, int stockQuantity) {
    this.id = id;
    this.name = name;
    this.price = price;
    this.stockQuantity = stockQuantity;
  }
}

4. H2 DB에 insert할 데이터 스크립트를 작성한다.

src/main/resources 디렉터리에 import.sql 파일을 추가하고 insert문을 작성한다.
주의할 점은 hibernate로 스키마를 생성하는 경우, 파일명이 import.sql이어야 한다. 처음에 SQL Script 방식을 따라 data.sql로 생성했더니 테이블만 생성되고 데이터는 비어있었다.

INSERT INTO item (item_id, name, price, stock_quantity) VALUES (768848, '오리털 잠바', 21000, 45);
INSERT INTO item (item_id, name, price, stock_quantity) VALUES (748943, '잠옷 세트', 19000, 89);
INSERT INTO item (item_id, name, price, stock_quantity) VALUES (779989, '남성 반팔티', 35000, 43);

5. IDE와 H2 GUI에서 데이터 생성을 확인한다.

애플리케이션이 실행되면 IDE 콘솔에서 DDL 쿼리를 확인할 수 있다. 쿼리 수행 방식을 create로 설정했기 때문에 drop 이후 create가 실행된다.

image

yml에 H2 GUI을 활성화하고 path를 /h2-console로 지정했으므로 localhost:8080/h2-console로 접속이 가능하다. 초기 접속 화면이 뜨고, password는 따로 설정하지 않았으므로 Conncet를 눌러 H2 DB에 접속한다.

image

select문으로 조회하면 아래와 같이 데이터가 잘 생성되었다.

image

그런데 난 분명히 entity 클래스를 id 먼저 작성했는데 왜 컬럼 순서가 제멋대로 생성되었지? Spring Data JPA는 테이블을 생성할 때 컬럼을 알파벳 순으로 자동 정렬해준다고 한다. 따라서 개발자가 설계한 대로 컬럼 순서를 정할 수 없다는 것. 실제라면 기획대로 설계가 안된 것이기 때문에, DDL문도 스크립트로 작성해서 스키마를 생성하기로 했다. 다행히 변경할 곳은 많지 않았다.

SQL script을 사용한 h2 DB 초기화 방법

1. application.yml에 ddl-auto를 none으로 변경한다.

none으로 설정하면 스키마 생성을 hibernate가 아니라 schema.sql 파일이 담당하게 된다. hibernate로 DB를 초기화하지 않을 것이므로 defer.datasource.initialization은 제거 또는 주석 처리한다.

spring:
  datasource:
    url: jdbc:h2:mem:test
    username: sa
    password:
    driver-class-name: org.h2.Driver
  h2:
    console:
      enabled: true
      path: /h2-console
  jpa:
    hibernate:
      ddl-auto: none //create에서 none으로 수정
    properties:
      hibernate:
        format_sql: true
        show_sql: true
#    defer:
#      datasource:
#        initialization: true //주석 처리로 SQL Scripts 방식 사용

2. 스키마 생성 스크립트를 작성한다.

  • src/main/resources에 schema.sql 파일을 추가하고 아래와 같이 create문을 작성한다.
CREATE TABLE item
(
    item_id bigint NOT NULL PRIMARY KEY,
    name varchar(255) NOT NULL,
    price integer NOT NULL,
    stock_quantity integer NOT NULL
);

3. 데이터 스크립트 파일명을 import.sql에서 data.sql로 변경한다.

  • 앞서 설명했듯이 SQL Scripts 초기화 방식에서는 data.sql을 찾아 데이터를 생성한다.
  • 애플리케이션을 실행해보면 hibernate의 DDL 쿼리는 실행되지 않고, H2 Console에는 테이블과 데이터가 잘 생성된 것을 확인할 수 있다.

image

image

reference

https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.data-initialization https://www.sktenterprise.com/bizInsight/blogDetail/dev/6795