[Spring Batch] 스프링 배치 메타테이블(BATCH_*)이 안 만들어질 때, Job Bean 이 자동 실행이 안될 때

민지·2025년 8월 23일
0

Spring

목록 보기
33/37

✔️ Spring Batch 메타테이블

BATCH_JOB_INSTANCE, BATCH_JOB_EXECUTION, BATCH_STEP_EXECUTION 같은 테이블은 Spring Batch 가 Job 실행 상태를 관리하기 위해 필요하고, 이 테이블들은 우리가 직접 SQL 로 만들지 않아도 Spring Boot/Spring Batch 가 자동으로 생성해준다.

자동 생성 방법

application.yml 에서 아래 설정을 추가해주면
애플리케이션 실행 시 BATCH 메타 테이블들이 MySQL 에 자동 생성된다.

spring:
  batch:
    jdbc:
      initialize-schema: always

always 로 두면 Spring Boot 가 org/springframework/batch/core/schema-mysql.sql 파일을 읽어서 MySQL에 BATCH_ 테이블들을 자동으로 만들어준다.


메타 테이블 생성 에러

Caused by: org.springframework.jdbc.support.MetaDataAccessException: Could not get Connection for extracting meta-data

이 에러는 DB 연결이 정상적으로 이루어지지 않아서 메타데이터(테이블, 컬럼 정보 등)를 읽어오지 못할 때 발생한다.

Caused by: org.hibernate.HibernateException: Unable to determine Dialect without JDBC metadata (please set 'jakarta.persistence.jdbc.url' for common cases or 'hibernate.dialect' when a custom Dialect implementation must be provided)

이 에러는 Hibernate 가 어떤 종류의 데이터베이스를 사용하고 있는지 알 수 없을 때 발생한다.

데이터베이스 연결 정보나 Dialect 를 명확하게 지정해주면 해결된다. application.properties 또는 application.yml 파일에 데이터베이스 URL(jakarta.persistence.jdbc.url)을 설정하거나 직접 사용할 Dialect을 지정해주는 hibernate.dialect 속성을 추가해줘야 한다.

DB URL (application.yml 에 추가)

spring:
          datasource:
            url: jdbc:mysql://localhost:3306/your_database_name?zeroDateTimeBehavior=convertToNull&characterEncoding=UTF-8&serverTimezone=Asia/Seoul
            username: user 이름 입력
            password: 패스워드 입력

application.properties 에 추가한다면

spring.datasource.url=jdbc:mysql://localhost:3306/your_database_name?zeroDateTimeBehavior=convertToNull&characterEncoding=UTF-8&serverTimezone=Asia/Seoul
        spring.datasource.username=user 이름 입력
        spring.password=패스워드 입력

DB URL 을 설정한 후에도 에러가 해결되지 않는다면 Dialect를 직접 지정해야 한다.

Dialect 직접 지정 (application.yml 에 추가)

사용하는 데이터베이스에 맞는 Dialect 클래스를 선택하면 된다. (예시 MySQL)

spring:
          jpa:
            properties:
              hibernate:
                dialect: org.hibernate.dialect.MySQLDialect

application.properties 에 추가한다면

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect

배치 테이블이 드디어 생겼다 😂
근데 테이블은 만들어졌는데 아무 데이터 값이 들어오지 않는다. Job 이 실행되어야 BATCH_JOB_INSTANCE, BATCH_JOB_EXECUTION, BATCH_STEP_EXECUTION 등에 기록이 들어가는데 지금은 Job 이 실행 되지 않았기 때문에 테이블은 비어있는 것이다.



✔️ Job Bean 자동 실행

1. Job Bean 이름과 spring.batch.job.name 이 일치해야 함

Spring Boot 는 시작할 때 applicationContext 에 등록된 Job 들을 확인한다. 애플리케이션 시작과 동시에 Job 이 실행되도록 하는 방법은 spring.batch.job.enabled=true 를 설정해주는 것이다. spring.batch.job.name 은 실행할 Job 이 하나일 때만 설정해주면 된다. properties 파일 또는 yml 파일에 추가해주면 된다.

application.properties 에 추가한다면

spring.batch.job.name=passJob
spring.batch.job.enabled=true

application.yml 에 추가한다면

spring:
  batch:
    job:
      enabled: true
      name: passJob

Spring Batch 애플리케이션을 그냥 main() 실행만 하면 Spring Boot Context 와 Batch 인프라(JOB REPOSITORY, TRANSACTION 등)는 등록이 되지만, Job 자체는 자동 실행이 되지 않는다. Batch Job 을 자동 실행하려면 JobLauncherApplicationRunner 가 빈으로 등록되어 있어야 한다. JobLauncher 를 통해 Job 을 실행해야 Step 이 돌아가는 구조다. 이 빈이 spring.batch.job.enabled=true 설정을 보고 Job 을 실행시킨다.


2. Bean 은 @SpringBootApplication 클래스 안에 등록되어야 함

Application 클래스가 @SpringBootApplication 이고 같은 패키지 안에 Bean 등록이 되어 있어야 한다. 만약 패키지 구조가 다르면 컴포넌트 스캔 범위 밖이어서 실행되지 않을 수 있다.

추가적으로 @EnableBatchProcessing 은 기본 Batch 인프라(JobRepository, JobLauncher, JobExplorer, JobRegistry 등)를 자동으로 등록해주는 역할을 한다. Spring Boot 3 부터는 spring-boot-starter-batch 의존성이 기본적으로 자동으로 구성해주기 때문에 꼭 붙이지 않아도 돼서 JobLauncher 충돌이 사라졌다.
Batch Starter 와 spring.batch.job.enabled: true 로 설정해주었다면 자동 실행에 직접 JobLauncher 를 사용할 필요는 없다.


3. JobParameters 중복 문제 해결

Spring Batch 는 이미 같은 파라미터로 실행된 기록이 있으면 AlreadyCompletedException 발생하거나 Job 이 실행되지 않는다. 자동 실행 시도할 때도 동일하게 JobParameters 가 없으면 실행 안 되는 경우가 생긴다.
이런 경우 Job 에 RunIdIncrementer 를 추가하면 매 실행마다 내부적으로 incrementing ID 를 붙여주어 중복 문제를 회피할 수 있다.

@Bean
public Job passJob(JobRepository jobRepository, Step passStep) {
    return new JobBuilder("passJob", jobRepository)
            .incrementer(new RunIdIncrementer()) //여기
            .start(passStep)
            .build();
}

4. JobLauncherApplicationRunner 명시적 실행

(Spring Boot 3 + Spring Batch 5 환경임)

  • spring-boot-starter-batch 의존성 추가 되어있음
  • Job 과 Step 을 @Bean 으로 등록 되어있음
  • JobRepository 와 PlatformTransactionManager 를 직접 주입받아 JobBuilder, StepBuilder 생성했음
  • spring.batch.job.enabled=true 설정 되어있음
  • Job 이 하나라 spring.batch.job.name=passJob 도 설정 되어있음
  • JobParameters 중복일까 싶어 Job 에 RunIdIncrementer() 를 붙임
  • yml 의 spring.batch.job.name 과 Job Bean 이름 일치함

되어 있는 설정으로는 자동 실행돼야 정상인데,

JobLauncherApplicationRunner 는 원래 별도로 클래스를 만들 필요가 없지만 실행되지 않고 실행할 Job 을 못 찾고 있다면 ApplicationRunner 를 통해 직접 JobLauncher 를 실행시켜줘야 된다. Job 이 확실히 실행되고 JobParameters 도 직접 관리 가능하고 배치 재실행, 재시도, 장애 대응이 쉬운 장점이 있다. 오히려 자동 실행보다 안정적일 수 있다.

@Bean
    public ApplicationRunner runJob(Job passJob, JobLauncher jobLauncher) {
        return args -> {
            jobLauncher.run(passJob, new JobParametersBuilder()
                    .addLong("run.id", System.currentTimeMillis()) // 매번 유니크한 파라미터
                    .toJobParameters());
        };
    }

Application.java 에 JobLauncher 를 추가해줬더니 메타 테이블에 드디어 데이터 값이 들어왔다. 이제 외부 DB 가 붙은 상태이다. 휴



JobLauncherApplicationRunner 가 자동 실행되지 않는 이유

1. Runner 가 실행되기 전에 애플리케이션 종료

Spring Boot 가 ApplicationContext 를 모두 초기화한 후, CommandLineRunner/ApplicationRunner 단계에서 JobLauncherApplicationRunner 가 Job 을 실행한다. 그런데 애플리케이션이 조기 종료되거나 Gradle/IDE 실행 모드에서 main 이 비동기적으로 종료되면 Runner 가 실행 기회를 갖지 못하고 애플리케이션이 종료된다.

2. Job Bean 조회 문제

JobLauncherApplicationRunner 는 Job Bean 을 Spring 컨텍스트에서 찾아서 실행한다. Job Bean 이 제대로 등록되지 않았거나 Bean 등록 시점이 늦으면 실행 되지 않는다. @Configuration 클래스가 여러개이면 Runner 가 Job 을 찾지 못하는 경우도 있다.

3. CommandLine 파라미터와 JobParameters 문제

spring.batch.job.name 을 지정하면 해당 Job 만 실행한다.
이미 DB에 같은 JobParameters 가 존재하면 JobLauncherApplicationRunner 는 중복 실행을 방지하기 위해 Job 실행을 스킵한다. RunIdIncrementer 가 있어도 Runner 가 실행 시점에 새 파라미터를 못 만드는 환경이라면 실행이 안 될 수도 있다.

profile
개발일지

0개의 댓글