다음은 배치를 사용하여 본격적인 서비스를 구현하기 전에 기본적인 이론과 5.0에서의 테스트를 미리 진행해보는 것을 목표로 한다.

Spring Batch란?

Batch는 대규모 데이터를 처리하거나, 일괄 처리 작업을 지원하는 Spring Framework의 하위 프로젝트 이다.
Batch를 이용해서 대규모 데이터 처리가 가능한 이유는, chunk 단위로 트랜잭션을 처리하기 때문인데,

@Transactional을 사용해보았다면 이해가 쉬울 것이다.
@Transactional을 가진 메서드를 호출할 때 프록시 객체(데이터베이스에 조회를 지연할 수 있는 가짜 객체)가 생성된다. 그리고 이떄 생성된 프록시 객체는 메서드를 실행하기 전 PlaformTransactionManeger를 통해 트랜잭션을 시작하고 결과에 따라 Commit 또는 Rollback한다.

우리가 Batch를 다루면서 할 것은 단순히 클래스를 프록시 객체로 만들어 트랜잭션을 실행하는 것이 아닌 사용할 PlatformTransactionManeger를 정하고 어떠한 단위로 트랜잭션을 처리할 지 정하는 것이라고 할 수 있다.

이때 실제 작업 수행 Chunk, 혹은 Tasklet을 통해 할 수 있는데, 이 둘을 비교하여 설명해보자.

Tasklet VS Chunk

간단하게 설명하자면 다음과 같다.

  • Tasklet은 RepeatStatus를 통해 작업 완료 여부만 잘 return하면 나머지 로직은 자유롭게 구성할 수 있다.
    -> 즉 Tasklet은 작업 완료 여부를 한 번만 결정할 수 있기 때문에 Tasklet 단위로 커밋된다.
  • Chunk는 Chunk의 크기를 정의함으로서 커밋의 간격을 정의할 수 있다.
    -> 작업 완료 여부가 Chunk 단위로 결정되며 재시도와 롤백이 가능해 일괄 처리시 유리하다.(정상적인 데이터를 중복해서 검사할 확률이 줄어든다.)

이 정도만 알아둔뒤, Job과 Step은 코드를 통해 알아보자

Spring Batch 5 에서 간단한 배치 구현

코드를 만들기 전, 알아둬야 할 것이 있다. Spring Batch 5의 경우 4와 다르게 사용하는 DataSource와 PlatformTransactionManeger를 명시해 줘야 한다.
이때 Spring Batch 4에서 자동 설정을 도와주던 @EnableBatchProcessing(5에선 못씀)의 대안으로 DefaultBatchConfiguration를 사용할 수 있지만, 이때 Job의 자동수행이 안된다
그리고 본래 H2 데이터 베이스를 연결하면 Batch에 필요한 데이터 테이블을 자동 생성 하지만, 5 부터는 안된다!! 따라서 우리는 defaultBatchConfiguration를 사용하지 않고 사용할 DataSource와 PlatformTransactionManeger를 빈으로 등록하거나, Job을 실행시킬 Runner를 별도로 만드는 방법을 사용해야한다.

yaml 파일

spring:
  datasource:
    url: jdbc:h2:~/mydb
    username: sugang_local
    password: 1234
    driver-class-name: org.h2.Driver

간단한 테스트를 목적으로 하는 만큼, 별도의 연결을 수행하지 않아도 되는 h2 db를 사용했다.

mainApplication

@SpringBootApplication
public class SugangBatchApplication{
	@Bean
	public DataSource batchDataSource() {
		return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)
				.addScript("/org/springframework/batch/core/schema-h2.sql")
				.generateUniqueName(true).build();
	}

	@Bean
	public JdbcTransactionManager batchTransactionManager(DataSource dataSource) {
		return new JdbcTransactionManager(dataSource);
	}

	@Bean
	public Step passStep(JobRepository jobRepository, PlatformTransactionManager transactionManager){
		return new StepBuilder("passStep",jobRepository)
				.tasklet(new Tasklet() {
					@Override
					public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
						System.out.println("Execute Tasklet");
						return null;
					}
				},transactionManager)
				.build();
	}

	@Bean
	public Job passJob(JobRepository jobRepository, JdbcTransactionManager transactionManager){
		return new JobBuilder("passJob", jobRepository)
				.start(passStep(jobRepository,transactionManager))
				.build();
	}
	public static void main(String[] args) {
		SpringApplication.run(SugangBatchApplication.class, args);
	}
}

별도의 Config를 구성하는 것이 좋지만, 테스트인 만큼 메인에 간단하게 구현했다. 메서드를 하나 씩 살펴보자.

public DataSource batchDataSource()

앞서 말했듯 Batch 5에서는 H2에 Batch에 필요한 스키마를 생성하는 과정이 선행되어야 한다. 별도의 initialize를 구성하는 방법도 있겠지만 https://medium.com/@aryan.shinde.29/configuring-dual-data-sources-in-spring-batch-5-and-spring-boot-3-8a72bc00555c 를 참고하여 스키마를 생성했다.

public JdbcTransactionManager batchTransactionManager(DataSource dataSource)

위에서 잠깐 언급하고 넘어갔던 JdbcTransactionManager가 우리가 설정한 H2를 사용하도록 만든다.

public Step passStep(JobRepository jobRepository, PlatformTransactionManager transactionManager)

사용할 JobRepository jobRepository, PlatformTransactionManager transactionManager를 정하고, Step을 생성한다. 이때 Step은 Chunk 단위가 아닌 tasklet을 사용했다. 람다식으로 만들면 아래와 같다.


@Bean
public Step passStep(JobRepository jobRepository, PlatformTransactionManager transactionManager){
	return new StepBuilder("passStep",jobRepository)
			.tasklet((contribution, chunkContext) -> {
			    System.out.println("Execute Tasklet");
			    return null;
			 },transactionManager)
			 .build();
	}

Batch 5에서는 사용할 transactionManger를 반드시 명시해야한다는 점을 제외하면 Batch4와 크게 달라진 점은 없다.

public Job passJob(JobRepository jobRepository, JdbcTransactionManager transactionManager)

Job은 여러개의 Step의 순서를 정하고 실행시킬 수 있다. Batch 5에서는 사용할 transactionManger를 반드시 명시해야한다는 점을 제외하면 Batch4와 크게 달라진 점은 없다.

이후 진행

과정을 보이기 위해 Tasklet만을 사용했으나, 다음 포스팅에서는 실제 개발을 하며 Chunk에 대한 예제를 보일 예정이다. 또한 실제 개발하면서 생기는 문제들을 같이 알아보겠다.