[Spring Batch] 11.

개념

배치 작업 중 정보를 저장하기 위한 저장소 역할입니다.

배치 작업 실행과 관련된 모든 메타데이터를 저장합니다. B. 작업이 실행될 때, 종료될 때 실행 횟수 및 실행 결과.

– CRUD 기능은 JobLauncher, Job 및 Step 구현 내에서 처리됩니다.


인력 시장

작업 저장소

작업 저장소
부울 isJobInstanceExists(String jobName, JobParameters jobParameters) JobInstance가 있는지 확인하십시오.
JobExecution createJobExecution(String JobName, JobParameter JobParameter) 작업이 실행될 때마다 jobExecution 생성
JobExecution getLastJobExecution(String JobName, JobParameter JobParameter) 작업 실행 기록의 마지막 JobExecution을 반환합니다.
무효 업데이트(JobExecution jobExecution) 주문 실행 정보 업데이트
무효 업데이트(StepExecution stepExecution) 단계 실행 정보 업데이트
무효 추가(StepExectuion stepExectuion) 해당 실행 단계의 새로운 stepExectuion을 저장합니다.
무효 updateExecutionContext(StepExecution stepExecution) 단계의 공유 데이터 및 상태 정보가 포함된 실행 컨텍스트 업데이트
무효 updateExecutionContext(JobExecution jobExecution) 작업의 공유 데이터 및 상태 정보가 포함된 실행 컨텍스트 업데이트
StepExecution getLastStepExecution(JobInstance jobInstance, String stepName) 해당 단계의 실행 히스토리에서 마지막 StepExecution을 반환합니다.

JobRepository 설정

  • @EnableBatchProcessing을 선언하면 JobRepository가 자동으로 bean으로 생성된다.
  • BatchConfigurer 인터페이스를 구현하거나 BasicBatchConfigurer를 상속하여 JobRepository 설정을 사용자 지정할 수 있습니다.

1. JDBC 방식 설정

JobRepositoryFactoryBean

  • 내부적으로 트랜잭션은 AOP 기술을 통해 처리됩니다.
  • 트랜잭션 격리의 기본값은 SERIALIZEBLE이며 다른 수준(READ_COMMAND, REPEATABLE_READ)으로 설정할 수 있습니다.
  • 메타 테이블의 테이블 접두사를 변경할 수 있습니다. 기본값은 “BATCH_”입니다.

소스 코드

@Override
protected JobRepository createJobRepository() throws Exception {
    JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
    factory.setDataSource(dataSource);
    factory.setTransactionManager(transactionManager);
    factory.setIsolationLevelForCreate("ISOLATION_SERIALIZABLE"); // isolation 수준, 기본값은 “ISOLATION_SERIALIZABLE”
    factory.setTablePrefix(“SYSTEM_"); // 테이블 Prefix, 기본값은 “BATCH_”, BATCH_JOB_EXECUTION 가 SYSTEM_JOB_EXECUTION 으로 변경됨
    factory.setMaxVarCharLength(1000); // varchar 최대 길이(기본값 2500)
    return factory.getObject(); // Proxy 객체가 생성됨 (트랜잭션 Advice 적용 등을 위해 AOP 기술 적용)
}

기억에

MapJobRepositoryFactoryBean

  • 성능상의 이유로 도메인 개체를 DB에 저장하지 않으려는 경우
  • 일반적으로 신속한 테스트 또는 프로토타이핑이 필요할 때 사용됩니다.
@Override
protected JobRepository createJobRepository() throws Exception {
    MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean();
    factory.setTransactionManager(transactionManager); // ResourcelessTransactionManager 사용
    return factory.getObject();
}

소스 코드

JobRepositoryConfiguration.java

package io.springbatch.springbatchlecture;

import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@RequiredArgsConstructor
@Configuration
public class JobRepositoryConfiguration {

    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;
    private final JobRepositoryListener jobRepositoryListener;

    @Bean
    public Job BatchJob() {
        return this.jobBuilderFactory.get("Job")
                .start(step1())
                .next(step2())
                .listener(jobRepositoryListener)
                .build();
    }

    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1")
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                        return RepeatStatus.FINISHED;
                    }
                })
                .build();
    }
    @Bean
    public Step step2() {
        return stepBuilderFactory.get("step2")
                .tasklet((contribution, chunkContext) -> null)
                .build();
    }
}

CustomBatchConfigurer.java

package io.springbatch.springbatchlecture;

import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.boot.autoconfigure.batch.BasicBatchConfigurer;
import org.springframework.boot.autoconfigure.batch.BatchProperties;
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;

@Configuration
public class CustomBatchConfigurer extends BasicBatchConfigurer {

    private final DataSource dataSource;

    protected CustomBatchConfigurer(BatchProperties properties, DataSource dataSource, TransactionManagerCustomizers transactionManagerCustomizers) {
        super(properties, dataSource, transactionManagerCustomizers);
        this.dataSource = dataSource;
    }

    @Override
    protected JobRepository createJobRepository() throws Exception {

        JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
        factory.setDataSource(dataSource);
        factory.setTransactionManager(getTransactionManager());
        factory.setIsolationLevelForCreate("ISOLATION_SERIALIZABLE"); // isolation 수준, 기본값은 “ISOLATION_SERIALIZABLE”
        factory.setTablePrefix("BATCH_");  // 테이블 Prefix, 기본값은 “BATCH_”,
        // BATCH_JOB_EXECUTION 가 SYSTEM_JOB_EXECUTION 으로 변경됨
        // 실제 테이블명이 변경되는 것은 아니다
        factory.setMaxVarCharLength(1000); // varchar 최대 길이(기본값 2500)

        return factory.getObject(); // Proxy 객체가 생성됨 (트랜잭션 Advice 적용 등을 위해 AOP 기술 적용)

    }
}

JobRepositoryListener

package io.springbatch.springbatchlecture;

import org.springframework.batch.core.*;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class JobRepositoryListener implements JobExecutionListener {

    @Autowired
    private JobRepository jobRepository;

    @Override
    public void beforeJob(JobExecution jobExecution) {

    }

    @Override
    public void afterJob(JobExecution jobExecution) {

        String jobName = jobExecution.getJobInstance().getJobName();
        JobParameters jobParameters = new JobParametersBuilder().addString("requestDate", "20210102").toJobParameters();
        JobExecution lastExecution = jobRepository.getLastJobExecution(jobName, jobParameters);
        if(lastExecution != null) {
            for (StepExecution execution : lastExecution.getStepExecutions()) {
                BatchStatus status = execution.getStatus();
                System.out.println("BatchStatus = " + status.isRunning());
                System.out.println("BatchStatus = " + status.name());
            }
        }
    }
}

실행 결과

메타데이터 테이블이 “BATCH_”로 구성되어 있기 때문에 오류가 지속됩니다.