본문 바로가기
Development/Spring Batch

6. Spring Batch 청크 프로세스 활용 Step4 - JdbcBatchItemWriter / JpaItemWriter / ItemWriterAdapter

by 개발여행자 2022. 10. 3.

지금까지 ItemReader 구현체들을 통해서 DB에 있는 데이터들을 갖고오는 과정들을 진행했다면,

이번 시간에는 DB에 있는 데이터들을 갖고와서 DB에 저장하는 방법에 대해서 정리해 볼 생각이다.

ItemWriter와 같은 경우에도 ItemReader 구현체와 같이 여러 종류의 ItemReader의 구현체가 있지만, DB와 관련된 ItemWriter에 대해서만 정리해보자.

1. JdbcBatchItemWriter

  • JdbcCursorItemReader 설정과 마찬가지로 datasource를 지정하고, sql 속성에 실행할 쿼리를 설정
  • JDBC의 batch 기능을 사용하여 bulk insert/update/delete 방식으로 처리
  • 단건 처리가 아닌 일괄처리이기 때문에 성능에 이점을 가진다
  • JdbcBatchItemWriter 소스로 구현해보기
    • 아래 소스는 기존 customer 테이블에서 조건에 맞는 데이터를 갖고와서 customer2 테이블에 넣는 소스
@Configuration
@RequiredArgsConstructor
public class JdbcBatchConfiguration {
    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;
    private int chunkSize = 2;
    private final DataSource dataSource;

    @Bean
    public Job job() throws Exception {
        return jobBuilderFactory.get("JpaBatchJob")
                .start(step1())
                .build();
    }

    @Bean
    public Step step1() throws Exception {
        return stepBuilderFactory.get("step1")
                .<Customer, Customer>chunk(chunkSize)
                .reader(customItemReader())
                .writer(customItemWriter())
                .build();
    }

    @Bean
    public ItemWriter<? super Customer> customItemWriter() {
        return new JdbcBatchItemWriterBuilder<Customer>()
                .dataSource(dataSource)
                .sql("insert into customer2 values (:id, :firstname, :lastname, :birthdate)")
                .beanMapped()
                .build();
    }

    @Bean
    public JdbcPagingItemReader<Customer> customItemReader() throws Exception {
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("firstname", "A%");

        return new JdbcPagingItemReaderBuilder<Customer>()
                .name("jdbcPagingReader")
                .pageSize(chunkSize)
                .dataSource(dataSource)
                .rowMapper(new BeanPropertyRowMapper<>(Customer.class))
                .queryProvider(createQueryProvider())
                .parameterValues(parameters)
                .build();
    }

    @Bean
    public PagingQueryProvider createQueryProvider() throws Exception {
        SqlPagingQueryProviderFactoryBean queryProvider = new SqlPagingQueryProviderFactoryBean();
        queryProvider.setDataSource(dataSource);
        queryProvider.setSelectClause("id, firstname, lastname, birthdate");
        queryProvider.setFromClause("from customer");
        queryProvider.setWhereClause("where firstname like :firstname");

        Map<String, Order> sortKeys = new HashMap<>();
        sortKeys.put("id", Order.ASCENDING);
        queryProvider.setSortKeys(sortKeys);

        return queryProvider.getObject();
    }
}

 

2. JpaItemWriter

  • JPA Entity 기반으로 데이터를 처리하며 EntityManagerFactory를 주입받아 사용
  • Entity를 하나씩 chunk 크기만큼 insert 혹은 merge 한 다음 flush 한다
  • ItemReader 또는 ItemProcessor로 부터 아이템을 전달받을 때는 Entity 클래스 타입으로 받아야 한다

3. ItemWriterAdapter

  • 배치 Job 안에서 이미 있는 DAO 나 다른 서비스를 ItemWriter 안에서 사용하고자 할 때 위임 역할을 한다