41

I am currently writing a Spring batch where I am reading a chunk of data, processing it and then I wish to pass this data to 2 writers. One writer would simply update the database whereas the second writer will write to a csv file.

I am planning to write my own custom writer and inject the two itemWriters in the customItemWriter and call the write methods of both the item writers in the write method of customItemWriter. Is this approach correct? Are there any ItemWriter implementations available which meet my requirements?

Thanks in advance

6 Answers 6

32

You can use Spring's CompositeItemWriter and delegate to it all your writers.
here is a configuration example.

4
18

You don't necessarily have to use xml like the example. If the rest of your code uses annotation, you could simply do the following.

public ItemWriter<T> writerOne(){
    ItemWriter<T> writer = new ItemWriter<T>();
    //your logic here
    return writer;
}

public ItemWriter<T> writerTwo(){
    ItemWriter<T> writer = new ItemWriter<T>();
    //your logic here
    return writer;
}

public CompositeItemWriter<T> compositeItemWriter(){
    CompositeItemWriter writer = new CompositeItemWriter();
    writer.setDelegates(Arrays.asList(writerOne(),writerTwo()));
    return writer;
}
1
  • Anyone knows how to mix tipes? e.g. if you make writerOne typed T and writerTwo typed u.
    – Vincent
    Mar 17, 2023 at 13:34
4

You were right. SB is heavly based on delegation so using a CompositeItemWriter is the right choice for your needs.

1
  • do you know how to achieve this by multi threading the writers?
    – kaissun
    Mar 27, 2017 at 11:10
2

Java Config way SpringBatch4

@Bean
    public Step step1() {
            return this.stepBuilderFactory.get("step1")
                                    .<String, String>chunk(2)
                                    .reader(itemReader())
                                    .writer(compositeItemWriter())
                                    .stream(fileItemWriter1())
                                    .stream(fileItemWriter2())
                                    .build();
    }

    /**
     * In Spring Batch 4, the CompositeItemWriter implements ItemStream so this isn't
     * necessary, but used for an example.
     */
    @Bean
    public CompositeItemWriter compositeItemWriter() {
            List<ItemWriter> writers = new ArrayList<>(2);
            writers.add(fileItemWriter1());
            writers.add(fileItemWriter2());

            CompositeItemWriter itemWriter = new CompositeItemWriter();

            itemWriter.setDelegates(writers);

            return itemWriter;
    }
1
0

Depending on your need, another option is to extend the Writer class and add functionality there. For example, I have a project where I am extending HibernateItemWriter and then overriding write(List items). I then send the objects I am writing along with my sessionFactory to the doWrite method of the Writer: doWrite(sessionFactory, filteredRecords).

So in the example above, I could write to the csv file in my extended class and then the HibernateItemWriter would write to the database. Obviously this might not be ideal for this example, but for certain scenarios it is a nice option.

0

Here's a possible solution. Two writers inside a Composite Writer.

    @Bean
public JdbcBatchItemWriter<XPTO> writer(DataSource dataSource) {        
    return new JdbcBatchItemWriterBuilder<XPTO>()
            .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
            .sql("UPDATE xxxx")
            .dataSource(dataSource)             
            .build();
}

@Bean
public JdbcBatchItemWriter<XPTO> writer2(DataSource dataSource) {           
    return new JdbcBatchItemWriterBuilder<XPTO>()
            .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
            .sql("UPDATE yyyyy")
            .dataSource(dataSource)             
            .build();
}

@Bean
public CompositeItemWriter<XPTO> compositeItemWriter(DataSource dataSource) {
    CompositeItemWriter<XPTO> compositeItemWriter = new CompositeItemWriter<>();
    compositeItemWriter.setDelegates(Arrays.asList( writer(dataSource), writer2(dataSource)));
    return compositeItemWriter;
}

@Bean
protected Step step1(DataSource datasource) {
    
    return this.stepBuilderFactory.get("step1").
            <XPTO, XPTO>chunk(1).
            reader(reader()).
            processor(processor()).             
            writer(compositeItemWriter(datasource)).
            build();

}   
2
  • Per the qtn, one should write to DB while other to CSV. But your example shows both updating DB only Feb 9, 2021 at 1:31
  • The updates of my example just shows how to UPDATE two different tables. Could be a DB and a CSV? Of course! Feb 9, 2021 at 1:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.