728x90
Spring Batch 코드 작성 후 실행 시 Table doesn't exist 에러 해결
1. 기존 코드
- 매일 새벽마다 외부 Open API와 통신해 DB값을 업데이트해야 하는 배치 프로세스를 추가했다.
- 코드를 전부 작성하고 실행하니 아래와 같이 테이블이 존재하지 않는다는 에러 메시지가 출력됐다.
2. 문제 분석
1. Spring Batch 사용할 때 Batch용 테이블이 필요한 이유
- Spring Batch를 사용할 때 Batch 관련 테이블이 중요한 역할을 하는 이유는 상태 관리, 실패한 작업의 재시도, 성능 모니터링, 일괄 처리 통계와 같은 기능들을 제공하기 때문이다.
- 이러한 테이블들은 Batch Job의 실행에 대한 로깅, 실행 이력, 성공/실패 상태, 현재 진행 중인 Step 정보 등을 저장한다.
- 이 정보는 Batch 프로세스가 예상대로 동작하는지 확인하고, 문제 발생 시 문제를 진단하고 해결하는 데 필수적이다.
2. 그러나, 테이블이 필요 없는 경우도 존재한다.
- 하지만 모든 경우에 Batch 관련 테이블이 필요한 것은 아니다.
- 간단한 배치 작업이나 단일 실행으로 끝나는 작업, 또는 작업의 실행 이력이 중요하지 않은 경우에는 이 테이블들 없이도 Batch Job을 실행할 수 있다.
- 이런 경우에는 메타데이터 테이블을 사용하지 않도록 Spring Batch 설정을 변경할 수 있다. 그러나 이렇게 설정하면 상태 추적이나 재실행과 같은 기능을 사용할 수 없게 되므로, 오류 발생 시 문제를 해결하기가 더 어려워질 수 있다.
- 예를 들어, 단순히 매일 특정 시간에 데이터베이스에서 데이터를 읽어와서 처리하고 결과를 저장하는 작업이 있을 때는, 이 작업의 실패 여부나 이력을 추적할 필요가 없다면 Batch 관련 테이블 없이도 충분할 수 있다.
- 테이블 없이 Batch를 진행시키려면 MapJobRepositoryFactoryBean을 사용하여 인메모리 JobRepository를 설정할 수 있다. 이 설정은 테스트나 단순한 작업에는 적합할 수 있지만, 지속성이 없으므로 프로덕션 환경에서는 권장되지 않는다.
@Bean
public JobRepository jobRepository() throws Exception {
MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean();
return factory.getObject();
}
- 이렇게 하면 메타데이터를 인메모리에 저장하게 되므로, 별도의 데이터베이스 테이블은 필요하지 않다. 다만 이 방법은 상태 유지가 중요한 복잡한 배치 작업에는 적합하지 않을 수 있다.
결론적으로, 일반적으로는 장애 발생 시 신속한 대응을 위해, 또한 작업의 성공적인 완료를 보증하기 위해 Batch 관련 테이블을 유지하는 것이 좋다.
3. 그럼 Spring Batch가 자동으로 전용 DB Table을 생성하는가?
- Spring Batch는 기본적으로 작업(Job)의 상태와 메타데이터를 저장하기 위해 몇 가지 데이터베이스 테이블을 사용한다. 그러나 이 테이블들은 Spring Batch가 자동으로 생성하는 것은 아니다.
- 대신, Spring Batch는 이러한 테이블의 스키마를 정의한 SQL 스크립트를 제공한다. 이 스크립트를 사용하여 수동으로 테이블을 생성할 수 있다.
- 또한, Spring Boot를 사용하고 있고, spring-boot-starter-data-jpa 또는 spring-boot-starter-data-jdbc 의존성을 추가한 경우, Spring Boot의 자동 구성(auto-configuration) 기능이 이러한 테이블을 자동으로 생성할 수 있다.
- 이는 spring.datasource 설정이 적절히 구성되어 있고, 데이터베이스가 이러한 DDL(Data Definition Language) 작업을 허용하는 경우에만 가능하다.
따라서 Spring Batch가 "자동으로 전용 DB를 생성한다"라고 말하기보다는, "Spring Batch가 필요로 하는 테이블 스키마를 제공하고, 이를 사용자가 데이터베이스에 적용해야 한다"라고 말하는 게 더 정확한 표현이다.
3. 문제 해결
테이블을 자동으로 생성하려면 application.properties 또는 application.yml 파일에 다음과 같은 설정을 추가할 수 있다.
spring:
batch:
jdbc:
initialize-schema: always
위 설정을 추가하고 프로젝트를 실행시키면 아래와 같이 테이블이 생성되는 쿼리를 볼 수 있다.
그리고 DB에도 테이블이 잘 생성된 모습을 확인할 수 있다.
3-1. 그럼 spring: batch: jdbc: initialize-schema: always라고 작성하면 프로젝트 실행 때마다 매번 테이블이 생성되는가?
- spring.batch.jdbc.initialize-schema 설정은 Spring Batch가 시작될 때 데이터베이스 스키마를 초기화하는 방법을 결정한다.
- always 옵션을 사용하면 애플리케이션이 시작될 때마다 Spring Batch가 필요로 하는 테이블들을 생성한다.
- 그러나 이 설정이 실제로 기존 데이터를 삭제하고 테이블을 재생성하는지 여부는 사용하는 데이터베이스 유형과 Spring Batch 버전에 따라 다를 수 있다.
- 대부분의 경우, initialize-schema 옵션이 always로 설정되어 있으면, Spring Batch는 애플리케이션이 시작될 때마다 스키마를 생성하는 SQL 스크립트를 실행한다.
- 그런데 여기서 중요한 것은, 데이터베이스에 이미 스키마가 존재하는 경우 대부분의 데이터베이스는 기존 테이블을 다시 생성하려고 할 때 오류를 발생시키고, 스크립트 실행을 중단한다. 즉, 기본적으로 데이터가 삭제되거나 테이블이 재생성되지는 않는다.
- 그러나 실제로 테이블이 삭제되고 재생성되는 경우는 다음과 같은 특별한 상황이다:
- 데이터베이스가 메모리 내 데이터베이스인 H2, HSQLDB와 같은 경우로, 애플리케이션이 종료될 때 데이터베이스의 내용이 모두 사라진다.
- 사용자 정의 스크립트를 사용하여 initialize-schema가 호출될 때마다 테이블을 드롭하고 다시 생성하도록 지정한 경우.
- 일반적인 상용 데이터베이스(MySQL, PostgreSQL 등)에서는 initialize-schema: always 설정을 사용하지 않는다. 왜냐하면 이 설정은 개발 중이나 테스트할 때 유용하지만, 프로덕션 환경에서는 데이터 손실의 위험이 있기 때문이다.
- 프로덕션 환경에서는 다음과 같이 설정을 변경하는 것이 일반적이다:
spring:
batch:
jdbc:
initialize-schema: never
- 이렇게 설정하면 스프링 부트가 스키마를 자동으로 생성하지 않는다.
- 대신, 첫 배포 시에만 수동으로 스키마를 생성하고, 그 이후에는 애플리케이션이 데이터베이스 스키마를 건드리지 않도록 한다.
- 이 방법을 사용하면 데이터 손실을 방지하면서도 필요한 스키마만 정확히 설정할 수 있다.
3-2. BATCH_JOB_INSTANCE 테이블에 내가 설정한 job name 값이 잘 들어가 있는 걸 확인할 수 있다.
BatchConfig 클래스에 정의되어 있는 BatchJob Bean 등록 코드다.
💡 Spring Batch에서 Job을 구성할 때 JobBuilderFactory를 사용하는 것은 Job 인스턴스를 생성하고 관리하는 표준 방법이다.
JobBuilderFactory는 JobBuilder를 반환하는 메서드인 get()을 제공하는데, 이는 Job의 생성을 시작한다.
get("citationUpdateBatchJob") 메서드는 citationUpdateBatchJob이라는 이름의 JobBuilder를 생성한다.
이 이름은 Spring Batch의 메타데이터 테이블인 BATCH_JOB_INSTANCE에 job_name으로 저장된다.
BATCH_JOB_INSTANCE 테이블은 각각의 Job 인스턴스에 대한 메타데이터를 저장하는데, 여기에는 job_instance_id, job_name, job_key 등의 컬럼이 있다.
job_name 컬럼은 각 Job 인스턴스를 식별하는 데 사용되며, JobBuilder를 통해 생성된 Job의 이름으로 설정된다.
3-3. BATCH_JOB_EXECUTION_PARAMS 테이블에 내가 설정한 key_name 값이 잘 들어가 있는 걸 확인할 수 있다.
💡 위 코드에서는 JobParametersBuilder를 이용해 "citationUpdateJob"이라는 키에 현재 시간을 밀리초 단위의 문자열로 변환하여 값을 설정한다.
이렇게 생성된 JobParameters는 jobLauncher.run 메서드를 통해 citationUpdateJob을 실행할 때 인자로 전달된다.
BATCH_JOB_EXECUTION_PARAMS 데이터베이스 테이블에는 이렇게 전달된 매개변수가 기록되어, 나중에 Job 실행이 언제, 어떤 매개변수로 실행되었는지 추적할 수 있다.
"citationUpdateJob" 키는 BATCH_JOB_EXECUTION_PARAMS 테이블의 KEY_NAME으로 저장되며, 매 실행마다 고유한 값을 가지게 된다.
이는 JOB_NAME과는 다르게 실행 시점의 파라미터를 저장하는 용도다.
[Spring Boot] 의존성 버전문제로 인한 오류 해결
'Spring > Spring Boot' 카테고리의 다른 글
[Spring Boot] Spring Boot에서 Feign 클라이언트 사용하기(@FeignClient 사용 가이드) (2) | 2023.11.09 |
---|---|
[Spring Boot] 스프링 부트 프로젝트 실행하자마자 batch job이 실행되는 이슈 (0) | 2023.11.08 |
[Spring Boot] 의존성 버전문제로 인한 오류 해결 (1) | 2023.11.07 |
[Spring Boot] RequestDTO로 요청받을때 @RequestBody를 작성하는 경우와 작성하지 않는 경우 (1) | 2023.11.07 |
이해하기 쉬운 CORS 및 API 개발 안내서 (Access-Control-Allow-Headers) (1) | 2023.11.05 |