ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring Batch] CompositeItemWriter
    Study/Spring 2022. 6. 26. 20:06

    하나의 Step에서 여러개의 ItemWriter를 사용하는 방법

     

    Issue

    CompositeItemWriter에서 사용할 두 개의 writer 가 데이터를 받는 형식이 달라 문제가 발생하였다.

    이전에 겪었던 문제에서 들었던 예시로 설명해보면 다음과 같다.

    • Sentence를 Reader에서 읽고
    • 띄어쓰기를 기준으로 Processor에서 Split해서 Word 들을 생성하고
    • Writer에서는 List<Word>를 받는 상황

    이때, Writer를 두 개 생성하여 하나는 word를 저장하고 나머지는 문장이 처리 완료되었다고 sentence_id를 기준으로 상태값을 업데이트 한다고 해보자. (하나의 sentence에서 split된 word는 같은 sentence_id를 가지고 있다.)

    jdbcBatchItemListWriter는 앞서 재정의했던 JdbcBatchItemListWriter를 사용해서 Processor로 부터 List<Word> 값을 받아서 insert 쿼리를 실행하고,

    jdbcBatchListOfFirstItemWriter는 sentence_id를 기준으로 값을 업데이트한다. 문제는 writer가 받는 데이터 포맷을 통일해야 하기 때문에 jdbcBatchListOfFirstItemWriter에서도 List<Word>를 받아야한다.

    즉, JdbcBatchItemWriter로 jdbcBatchListOfFirstItemWriter를 만들 수 없다.

     

    JdbcBatchItemListWriter는 아래 링크 참고.

    https://gayeon-cs.tistory.com/97

     

    [Error 해결] JdbcBatchItemWriter로 리스트 처리하기

    Issue Spring Batch에서 기본적으로 제공하는 Writer인 JdbcBatchItemWriter로 리스트 값을 처리하려고 하자 문제가 생겼습니다. ItemReader와 ItemProcessor는 하나의 item을 처리하고 chunk단위로 item을 ItemW..

    gayeon-cs.tistory.com

     

    Solution

    JdbcBatchItemListWriter처럼 List<T> 형태로 Processor에서 데이터를 받는 JdbcBatchItemWriter를 상속받는 JdbcBatchListOfFirstItemWriter를 생성했다. 그리고, 해당 리스트의 첫번째 인덱스의 값만 update하도록 write 함수를 재정의 하였다.

    코드는 아래와 같다.

    import org.springframework.batch.item.database.JdbcBatchItemWriter;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    /*
    - Processor에서 List로 Entity를 전달하지만 첫번째 value만 처리하기 위해 write 함수 재정의
     */
    public class JdbcBatchListOfFirstItemWriter<T> extends JdbcBatchItemWriter<List<T>>  {
        private final JdbcBatchItemWriter<T> jdbcBatchItemWriter;
    
        public JdbcBatchListOfFirstItemWriter(JdbcBatchItemWriter<T> jdbcBatchItemWriter){
            this.jdbcBatchItemWriter = jdbcBatchItemWriter;
        }
    
        @Override
        public void write(List<? extends List<T>> items) {
            List<T> totalList = new ArrayList<>();
    
            for(List<T> list : items){
                totalList.addAll(Collections.singleton(list.get(0)));
            }
    
            try {
                jdbcBatchItemWriter.write(totalList);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
    }
    

    이용방법은 아래와 같다.

     

    @Bean		
    public Job job(){
        return jobBuilderFactory.get("job")
                .start(convertStep())
                .build();
    }
    
    @Bean
    public Step convertStep(){
        return stepBuilderFactory.get("convertStep")
                .<Sentence, List<Word>>chunk(chunkSize)
                .reader(jdbcCursorItemReader())
                .processor(processor)
                .writer(jdbcBatchItemListWriter())
                .build();
    }
    
    @Bean
    public CompositeItemWriter compositeItemWriter(){
        final CompositeItemWriter compositeItemWriter = new CompositeItemWriter<>()
        compositeItemWriter.setDelegates(Arrays.asList(jdbcBatchItemListWriter(), jdbcBatchListOfFirstItemWriter()));
        return compositeItemWriter;
    }
    
    public JdbcBatchItemListWriter<Word> jdbcBatchItemListWriter() {
        String insertWordQuery = "INSERT INTO word_tb(word) VALUES (:word)";
    
        JdbcBatchItemWriter<Word> writer = new JdbcBatchItemWriter<>();
        writer.setDataSource(dataSource);
        writer.setSql(insertWordQuery);
        writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>());
        writer.afterPropertiesSet();
        return new JdbcBatchItemListWriter<>(writer);
    }
    
    	public JdbcBatchListOfFirstItemWriter<Word> jdbcBatchListOfFirstItemWriter() {
            String insertWordQuery =
                    "UPDATE status SET work_state = 'C' WHERE id = :sentence_id";
    
            JdbcBatchItemWriter<Word> writer = new JdbcBatchItemWriter<>();
            writer.setDataSource(dataSource);
            writer.setSql(insertWordQuery);
            writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>());
            writer.afterPropertiesSet();
            return new JdbcBatchListOfFirstItemWriter<>(writer);
        }

    'Study > Spring' 카테고리의 다른 글

    [Error 해결] JdbcBatchItemWriter로 리스트 처리하기  (0) 2022.06.26
    JdbcTemplate  (0) 2022.06.22
    [Spring] DI (Dependency Injection) 개념과 예제  (0) 2021.02.15
    [Spring] Spring 이란  (0) 2021.01.25
Designed by Tistory.