ItemWriter interface
- ItemWriter는 마지막으로 배치 처리 대상 데이터를 어떻게 처리할 지 결정한다.
- DB에 데이터를 저장하거나, API로 서버에 요청하거나, 파일에 데이터를 write하거나 최종적으로 할 작업을 진행한다.
- Step에서 ItemWriter는 필수이다.
csvItemWriter
private ItemWriter<Person> csvItemWriter() throws Exception {
BeanWrapperFieldExtractor<Person> fieldExtractor = new BeanWrapperFieldExtractor<>();
fieldExtractor.setNames(new String[] {"id", "name", "age", "address"});
DelimitedLineAggregator<Person> lineAggregator = new DelimitedLineAggregator<>();
lineAggregator.setDelimiter(",");
lineAggregator.setFieldExtractor(fieldExtractor);
FlatFileItemWriter<Person> itemWriter = new FlatFileItemWriterBuilder<Person>()
.name("csvFileItemWriter")
.encoding("UTF-8")
.resource(new FileSystemResource("output/test-output.csv"))
.lineAggregator(lineAggregator)
.headerCallback(writer -> writer.write("id,이름,나이,거주지"))
.footerCallback(writer -> writer.write("---------------\n"))
.append(true)
.build();
itemWriter.afterPropertiesSet();
return itemWriter;
}
- csv 파일에 작성할 데이터를 추출하기 위해서 fieldExtractor 객체가 필요하다.
- fieldExtractor로 필드명을 설정해 준다.
- 각 필드의 데이터를 하나의 라인에 작성하기 위해서 구분자가 필요하다 -> lineAggregator로 설정가능
- FileSystemResource 클래스로 어떤 경로에 파일을 생성할지 지정해준다.
- headerCallback를 통해서 헤더를 추가해준다.
- footerCallback를 통해서 푸터를 추가해준다.
- append를 안해주면 파일명이 같으면 덮어쓰기 된다.
- 풋터 뒤에 개행문자를 추가해 주는게 좋다.
jdbcItemWriter
@Bean
public Step jdbcBatchItemWriterStep(){
return stepBuilderFactory.get("jdbcBatchItemWriterStep")
.<Person, Person>chunk(10)
.reader(itemReader())
.writer(jdbcBatchItemWriter())
.build();
}
private ItemWriter<Person> jdbcBatchItemWriter() {
JdbcBatchItemWriter<Person> itemWriter = new JdbcBatchItemWriterBuilder<Person>()
.dataSource(dataSource)
.itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
.sql("insert into person(name, age, address) values(:name, :age, :address)")
.build();
itemWriter.afterPropertiesSet();
return itemWriter;
}
- Person 객체를 파라미터로 자동으로 생성할 수 있는 BeanPropertyItemSqlParameterSourceProvider를 설정해준다.
jpaItemWriter
@Bean
public Step jpaItemWriterStep() throws Exception {
return stepBuilderFactory.get("jpaItemWriterStep")
.<Person, Person>chunk(10)
.reader(itemReader())
.writer(jpaItemWriter())
.build();
}
private ItemWriter<Person> jpaItemWriter() throws Exception {
JpaItemWriter<Person> itemWriter = new JpaItemWriterBuilder<Person>()
.entityManagerFactory(entityManagerFactory)
.usePersist(true)
.build();
itemWriter.afterPropertiesSet();;
return itemWriter;
}
- select 쿼리가 매 요청마다 실행됨 -> jpaItemWriter는 별다른 설정 없이 실행할 경우 -> merge 메소드로 실행됨.
- merge 메소드는 update하거나 insert 할 수 있는 메서드이다. -> 수정대상인지 확인하기 위해서 select 메서드가 실행되는 것이다. -> 그렇기 때문에 select 메서드로 인해 성능문제가 발생할 수 있다.
- 위의 문제를 해결하기위해서 -> usePersist(true) 설정하면 select 메서드가 실행되지 않고 insert메서드만 실행되는 확인할 수 있다.