스프링 부트 3에서 스프링 배치와 JPA를 사용하여 배치 테이블 자동 생성하기
스프링 부트 3 버전에서 적용되는 스프링 배치 적용 방법에 변경 사항이 있다. 더 자세한 내용은 아래 링크에 작성해 놨다.
[Spring Boot] Spring Boot 3.X 버전에서 Spring Batch 적용하기
1. 스프링 부트 3에서의 스프링 배치 변경 사항
스프링 부트 3에서는 스프링 부트 2와 비교하여 몇 가지 중요한 변경점이 있다. 이 중 가장 눈에 띄는 점은 스프링 배치의 자동 구성이 비활성화된 것이다.
이전 버전인 스프링 부트 2에서는 batch.jdbc.initialize-schema: ALWAYS와 job.enabled: true 설정을 통해 스프링 배치 관련 DB 테이블을 자동으로 생성하고 작업을 활성화할 수 있었다. 하지만 스프링 부트 3에서는 이와 같은 자동 구성이 비활성화되어 있어, 이전과 같은 설정이 예상대로 작동하지 않는다.
특히, 스프링 부트 3에서는 @EnableBatchProcessing 어노테이션을 추가하는 것이 스프링 배치의 자동 구성 기능을 오히려 끄는 결과를 가져온다. 이 자동 구성 기능에는 메타데이터 테이블을 자동으로 생성하고 배치 작업을 시작할 때 자동으로 실행하는 기능이 포함되어 있어, 이 어노테이션을 사용하면 spring.batch.* 속성들이 더 이상 작동하지 않게 된다.
더욱이, 스프링 부트는 기본적으로 내장 데이터베이스를 사용할 때만 메타데이터 테이블을 생성하도록 설정되어 있다. spring.batch.initialize-schema=always와 같은 속성을 사용해도, 내장 데이터베이스가 아니면 스프링 부트가 자동으로 테이블을 생성하지 않을 수 있다.
GitHub나 Stack Overflow 같은 커뮤니티에서는 스프링 부트 3.0.0으로 업그레이드한 후 batch.jdbc.initialize-schema: always 설정에도 불구하고 메타 데이터 테이블이 생성되지 않는 문제에 대한 여러 보고가 있었다. 이는 스프링 부트 3에서의 변경 사항 때문에 발생한 것으로 보인다.
2. 스프링 부트 3에서 테이블 자동 생성하기 (2 가지 방법)
스프링 부트 3에서 PostgreSQL 데이터베이스에 테이블을 자동으로 생성하는 방법 중 하나는 스프링 배치의 메타데이터 스키마를 사용하는 것이다.
2-1. 스프링 배치 메타데이터 스키마 사용하기
스프링 배치는 데이터베이스에 필요한 테이블을 만드는 데 사용되는 SQL 스크립트를 제공한다. 이 스크립트들은 스프링 배치 코어 JAR 파일 안에 org.springframework.batch.core 패키지 내에 schema-*.sql 형태로 있다. 여기서 *는 사용하는 데이터베이스 종류를 나타내는데, 예를 들어 PostgreSQL을 사용한다면 schema-postgres.sql 파일을 찾을 수 있다.
해당 코드를 복사해서 직접 데이터베이스에서 실행하면 정상적으로 테이블이 생성된 모습을 확인할 수 있다.
schema-postgresql.sql 전체 코드
-- Autogenerated: do not edit this file
CREATE TABLE BATCH_JOB_INSTANCE (
JOB_INSTANCE_ID BIGINT NOT NULL PRIMARY KEY ,
VERSION BIGINT ,
JOB_NAME VARCHAR(100) NOT NULL,
JOB_KEY VARCHAR(32) NOT NULL,
constraint JOB_INST_UN unique (JOB_NAME, JOB_KEY)
) ;
CREATE TABLE BATCH_JOB_EXECUTION (
JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,
VERSION BIGINT ,
JOB_INSTANCE_ID BIGINT NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL,
START_TIME TIMESTAMP DEFAULT NULL ,
END_TIME TIMESTAMP DEFAULT NULL ,
STATUS VARCHAR(10) ,
EXIT_CODE VARCHAR(2500) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED TIMESTAMP,
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;
CREATE TABLE BATCH_JOB_EXECUTION_PARAMS (
JOB_EXECUTION_ID BIGINT NOT NULL ,
PARAMETER_NAME VARCHAR(100) NOT NULL ,
PARAMETER_TYPE VARCHAR(100) NOT NULL ,
PARAMETER_VALUE VARCHAR(2500) ,
IDENTIFYING CHAR(1) NOT NULL ,
constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ;
CREATE TABLE BATCH_STEP_EXECUTION (
STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,
VERSION BIGINT NOT NULL,
STEP_NAME VARCHAR(100) NOT NULL,
JOB_EXECUTION_ID BIGINT NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL,
START_TIME TIMESTAMP DEFAULT NULL ,
END_TIME TIMESTAMP DEFAULT NULL ,
STATUS VARCHAR(10) ,
COMMIT_COUNT BIGINT ,
READ_COUNT BIGINT ,
FILTER_COUNT BIGINT ,
WRITE_COUNT BIGINT ,
READ_SKIP_COUNT BIGINT ,
WRITE_SKIP_COUNT BIGINT ,
PROCESS_SKIP_COUNT BIGINT ,
ROLLBACK_COUNT BIGINT ,
EXIT_CODE VARCHAR(2500) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED TIMESTAMP,
constraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ;
CREATE TABLE BATCH_STEP_EXECUTION_CONTEXT (
STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
SERIALIZED_CONTEXT TEXT ,
constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID)
references BATCH_STEP_EXECUTION(STEP_EXECUTION_ID)
) ;
CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT (
JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
SERIALIZED_CONTEXT TEXT ,
constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ;
CREATE SEQUENCE BATCH_STEP_EXECUTION_SEQ MAXVALUE 9223372036854775807 NO CYCLE;
CREATE SEQUENCE BATCH_JOB_EXECUTION_SEQ MAXVALUE 9223372036854775807 NO CYCLE;
CREATE SEQUENCE BATCH_JOB_SEQ MAXVALUE 9223372036854775807 NO CYCLE;
2-2. 데이터베이스 테이블 자동 생성 설정하기
스프링 부트 3에서 테이블을 자동으로 생성하는 또 다른 방법은 데이터베이스 테이블 자동 생성 설정을 활용하는 것이다.
스프링 부트는 애플리케이션 시작 시 schema-@@platform@@.sql 스크립트를 자동으로 실행한다. 예를 들어 PostgreSQL을 사용한다면, schema-postgres.sql 파일에 스프링 배치 테이블 생성에 필요한 SQL 명령어를 넣고, 이 파일을 src/main/resources에 위치시키면 된다. (쿼리를 직접 짤 필요 없이 2-1에서 설명한 파일을 resources 바로 하위에 위치시키면 된다.)
💡 schema-postgres.sql 파일은 프로젝트의 src/main/resources 폴더 바로 아래에 위치시켜야 한다.
스프링 부트는 이 폴더를 리소스 디렉토리로 인식하고, 애플리케이션 시작 시 여기에 있는 SQL 스크립트 파일들을 자동으로 실행한다. 따라서 schema-postgres.sql 파일을 이 위치에 넣으면, 스프링 부트가 애플리케이션이 시작할 때 해당 SQL 스크립트를 실행하여 필요한 테이블을 데이터베이스에 생성한다.
그리고 application.properties나 application.yml 파일에서 JPA 설정을 넣어준다. 여기서는 데이터베이스 연결 정보와 JPA가 데이터베이스 스키마를 자동으로 생성하도록 하는 설정을 넣어줘야 한다.
spring:
datasource:
driver-class-name: org.postgresql.Driver
url: ${MEMBER_DB_URL}
username: ${DB_MASTER_USERNAME}
password: ${DB_MASTER_PASSWORD}
sql:
init:
mode: always
batch:
jdbc:
initialize-schema: always
jpa:
hibernate:
ddl-auto: update
open-in-view: false
show-sql: true
properties:
hibernate:
format_sql: true
default_batch_fetch_size: 10
highlight_sql: true
spring:sql:init 설정은 SQL 초기화를 담당한다. 'mode' 속성은 SQL 스크립트 실행 모드를 결정하며, 'always'로 설정하면 애플리케이션 시작 시 항상 SQL 스크립트가 실행된다. 이 설정은 src/main/resources 하위에 위치한 SQL 파일을 자동으로 실행하게 한다.
이 설정은 주로 개발 초기에 사용된다. 데이터베이스 스키마가 안정화되면, 'never'로 변경하거나 설정을 제거하는 것이 바람직하다.
이렇게 설정해 주고 실행하면 아래와 같이 정상적으로 동작하는 모습을 볼 수 있다.
스프링 부트 3에서 스프링 배치 테이블의 자동 생성 기능이 비활성화되면서, 처음에는 이 사실을 알지 못했어서 테이블 생성이 안 되는 원인을 찾느라 많은 시간을 썼다. 이전 버전에서는 잘 작동하던 설정이 갑자기 작동하지 않게 되어 당황스러웠고, 해결책을 찾기 위해 여러 방법을 시도해 봤지만 별다른 진전이 없었다.
스프링 부트 3에서 스프링 배치를 적용하는 방법에 대한 정보가 상대적으로 부족해 처음에는 막막했지만 결국 이 문제를 해결할 수 있는 방법을 찾아내고, 이 경험을 통해 얻은 지식을 다른 개발자들과 공유하고자 이 블로그 글을 작성하게 되었다.
이 글이 비슷한 문제에 직면한 다른 개발자들에게 도움이 되었으면 좋겠다.
이 포스트는 Team chillwave에서 사이드 프로젝트 중 적용했던 부분을 다시 공부하며 기록한 것입니다.
시간이 괜찮다면 팀원 '개발자의 서랍'님의 블로그도 한번 봐주세요 :)
'Spring > Spring Boot' 카테고리의 다른 글
[Spring Boot] SNS MessageAttributes를 이용한 분산 시스템 추적용 Trace Id 전달 방법 (0) | 2023.11.28 |
---|---|
[Spring Boot] 스프링 배치에서 chunk와 JPA pageSize 설정의 관계성 (0) | 2023.11.27 |
[Spring Boot] Spring Boot 3.X 버전에서 Spring Batch 적용하기 (0) | 2023.11.26 |
[Spring Boot] 분산 시스템에서의 SNS/SQS 메시지 처리: 단일 책임 원칙과 Zipkin의 Trace ID 에러 핸들링을 중심으로 (0) | 2023.11.24 |
[Spring Boot] Zipkin에서 URL 추적 설정: Sampler와 Sleuth를 활용한 스프링 부트 적용 (0) | 2023.11.22 |