Skip to content

Spring Batch Transaction 범위

moonyoung edited this page Oct 4, 2020 · 1 revision

💫Tasklet

Spring Batch에서는 Step에서 Tasklet(interface)을 실행한다. Tasklet은 기능을 수행하고, Step에서 Tasklet 앞/뒤로 원하는 작업을 하라고 이런 전략을 취하는 것 같다.

public interface Tasklet {
	@Nullable
	RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception;
}

Tasklet은 익명 클래스과 ChunkOrientedTasklet이 있다. 프로젝트에서는 ChunkOrientedTasklet을 사용했다.

    @Bean
    public Step crawlingStep() {
        return stepBuilderFactory.get("crawlingStep")
                .<Place, Optional<CrawlingResult>>chunk(batchConfiguration.getChunk())
                .reader(placeReader())
                .processor(instagramBatchProcessor)
                .writer(instagramBatchWriter)
                .build();
    }

요렇게 사용하면 chunkOrientedTasklet이 내부적으로 사용된다는 것이다!

💫 실험

공식 문서를 보면 chunk 단위가 하나의 트랜잭션으로 관리된다고 나와있다.

Chunk oriented processing refers to reading the data one at a time and creating 'chunks' that are written out within a transaction boundary.

즉 reader/processor가 item 당 1번씩 + writer가 chunk에 1번씩 이 전체가 하나의 트랜잭션이라는 것이다.

기존에는 Writer에 Transaction이 붙어있었는데 그렇다면 진짜 Writer에 Transcation이 없어도 의도한대로 동작할까?

//    @Transactional 트랜잭션 지우기!
    @Override
    public void write(List<? extends Optional<CrawlingResult>> items) {
    	int count = 0;
        for (CrawlingResult crawlingResult : items) {
        	// 저장 로직
        	count++;
        	if (i == 1) {
                throw  new RuntimeException();
            }
        }
    }

트랜잭션을 빼고 item을 1개만 저장한 뒤 예외를 던지도록 만들었다.

/*
	chunkSize : 2
	item 2개를 저장해둔다.
	실행 시작!
 */
assertThat(stepExecution.getWriteCount()).isEqualTo(0);
assertThat(stepExecution.getRollbackCount()).isEqualTo(1);

위 테스트가 통과한다. 즉 @Transaction이 없어도 chunk 단위가 하나의 트랜잭션으로 동작한다.

🤔 트랜잭션은 짧게 잡는 게 좋지 않나? writer만 하나의 트랜잭션으로 처리하지 않고 왜 chunk 단위 전체를 하나의 트랜잭션으로 잡을까

트랜잭션과 관련해서 잘못 이해한 것이 있었다. 트랜잭션은 그냥 rollback할 때만 사용했다. 하지만 트랜잭션은 논리적인 작업단위이다. 동시성 제어(동시에 row를 기록-갱신/삭제)할 수 없을 뿐 아니라 모순성이 없게 해준다. 예를 들어 내가 x라는 데이터를 select했으면 트랜잭션이 끝날 때까지 x 데이터를 수정/삭제할 수 없게 막아주다. 따라서 Spring Batch에서는 read한 데이터를 가지고 작업을 처리하는 순간에 수정/삭제할 수 없게 보장해주는 것이다.

  • 비관적 lock : Spring Batch에서 사용한 것처럼, 내가 사용한 데이터가 바뀌지 않게 lock 시켜놓는 방식
  • 낙관적 lock : 내가 read한 데이터가 바뀔 일이 없다고 가정하고 처리하는 방식
Clone this wiki locally