Spring Batch - How to read from One Table and Write Data into two different table

有些话、适合烂在心里 提交于 2021-02-19 06:10:54

问题


I'm using Spring Boot and Spring Batch to read data from One table of source database table and split the data and write it into two tables of target database.

I choose to use CompositeItemWriter for this, but CompositeItemWriter<?> only one type. I want to write few fields in one table and other fields into another table.

Say: OLD Customer and NEW Customer.

Error:

The constructor CustomerClassifier(JdbcBatchItemWriter, JdbcBatchItemWriter) is undefined

ClassifierCompositeItemApplication.java

@EnableBatchProcessing
@SpringBootApplication
public class ClassifierCompositeItemApplication {

private JobBuilderFactory jobBuilderFactory;
private StepBuilderFactory stepBuilderFactory;

public ClassifierCompositeItemApplication(JobBuilderFactory jobs, StepBuilderFactory steps) {
    this.jobBuilderFactory = jobs;
    this.stepBuilderFactory = steps;
}


@Value("classpath:input/customer.csv")
private Resource inputResource;

@Bean
@StepScope
public FlatFileItemReader<Customer> classifierCompositeWriterItemReader() {
    return new FlatFileItemReaderBuilder<Customer>()
            .name("customerFileReader")
            .resource(inputResource).delimited()
            .names(new String[] { "firstName", "middleInitial", "lastName", "address", "city", "state", "zip" })
            .targetType(Customer.class)
            .build();
}


@Bean
public ClassifierCompositeItemWriter<Customer> compositeItemWriter() throws IOException {
    final Classifier<Customer, ItemWriter<? super Customer>> classifier = new CustomerClassifier(
            this.customer1(null), this.customer2(null));

    return new ClassifierCompositeItemWriterBuilder<Customer>().classifier(classifier).build();
}



@Bean
public JdbcBatchItemWriter<Customer> customer1(DataSource dataSource) {
    return new JdbcBatchItemWriterBuilder<Customer>()
            .namedParametersJdbcTemplate(new NamedParameterJdbcTemplate(dataSource))
            .sql("INSERT INTO TBL_CUSTOMER_WRITER (firstname, middleinitial, lastname, address, city, " + "state, "
                    + "zipcode) " + "VALUES(:firstName, " + ":middleInitial, " + ":lastName, " + ":address, "
                    + ":city, " + ":state, " + ":zip)")
            .beanMapped().build();
}



@Bean
public JdbcBatchItemWriter<NewCustomer> customer2(DataSource dataSource) {
    return new JdbcBatchItemWriterBuilder<NewCustomer>()
            .namedParametersJdbcTemplate(new NamedParameterJdbcTemplate(dataSource))
            .sql("INSERT INTO TBL_CUSTOMER_WRITER (firstname, middleinitial, lastname, address, city, " + "state, "
                    + "zipcode) " + "VALUES(:firstName, " + ":middleInitial, " + ":lastName, " + ":address, "
                    + ":city, " + ":state, " + ":zip)")
            .beanMapped().build();
}



@Bean
public Step classifierCompositeWriterStep() throws IOException {
    return this.stepBuilderFactory.get("compositeWriterStep")
            .<Customer, Customer>chunk(10)
            .reader(this.classifierCompositeWriterItemReader())
            .writer(this.compositeItemWriter())
            .stream(this.customer1(null))
            .stream(this.customer2(null))
            .build();
}


@Bean
public Job classifierCompositeWriterJob() throws IOException {
    return this.jobBuilderFactory.get("compositeWriterJob").start(this.classifierCompositeWriterStep()).build();

}

public static void main(String[] args) {
    SpringApplication.run(ClassifierCompositeItemApplication.class, args);
}

}

CustomerClassifier.java

@AllArgsConstructor
public class CustomerClassifier implements Classifier<Customer, ItemWriter<? super Customer>> {
private static final long serialVersionUID = 1L;
private final ItemWriter<Customer> customer1;
private final ItemWriter<Customer> customer2;

@Override
public ItemWriter<? super Customer> classify(Customer customer) {
    if (customer.getState().matches("^[A-M].*")) {
        return customer1;
    } else {
        return customer2;
    }
}
}

回答1:


You can use a ClassifierCompositeItemWriter. This composite writer is designed to classify items and call a delegate item writer for each class.

So in your case, you can have am item writer for old customers and another one for new customers and warp them in a classifier item writer. You can use one of the Classifier implementations provided by Spring or create a custom one (for example an item processor cam flag your items as old/new and the classifier uses this flag to classify them).

EDIT: Add an example:

import java.util.Arrays;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ClassifierCompositeItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.batch.item.support.builder.ClassifierCompositeItemWriterBuilder;
import org.springframework.classify.Classifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableBatchProcessing
public class MyJob {

    @Bean
    public ItemReader<Customer> itemReader() {
        return new ListItemReader<>(Arrays.asList(new Customer("foo"), new Customer("bar")));
    }

    @Bean
    public ItemWriter<Customer> fooWriter() {
        return items -> {
            for (Customer item : items) {
                System.out.println("foo writer: item " + item.name);
            }
        };
    }

    @Bean
    public ItemWriter<Customer> barWriter() {
        return items -> {
            for (Customer item : items) {
                System.out.println("bar writer: item " + item.name);
            }
        };
    }

    @Bean
    public ClassifierCompositeItemWriter<Customer> classifierCompositeItemWriter() {
        final Classifier<Customer, ItemWriter<? super Customer>> classifier = 
                new CustomerClassifier(this.fooWriter(), this.barWriter());

        return new ClassifierCompositeItemWriterBuilder<Customer>()
                .classifier(classifier)
                .build();
    }

    @Bean
    public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
        return jobs.get("job")
                .start(steps.get("step")
                        .<Customer, Customer>chunk(5)
                        .reader(itemReader())
                        .writer(classifierCompositeItemWriter())
                        .build())
                .build();
    }

    public static void main(String[] args) throws Exception {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyJob.class);
        JobLauncher jobLauncher = context.getBean(JobLauncher.class);
        Job job = context.getBean(Job.class);
        jobLauncher.run(job, new JobParameters());
    }

    static class Customer {
        String name;

        public Customer(String name) {
            this.name = name;
        }
    }

    static class CustomerClassifier implements Classifier<Customer, ItemWriter<? super Customer>> {

        private ItemWriter<? super Customer> fooItemWriter;
        private ItemWriter<? super Customer> barItemWriter;

        public CustomerClassifier(ItemWriter<? super Customer> fooItemWriter, ItemWriter<? super Customer> barItemWriter) {
            this.fooItemWriter = fooItemWriter;
            this.barItemWriter = barItemWriter;
        }

        @Override
        public ItemWriter<? super Customer> classify(Customer customer) {
            return customer.name.startsWith("f") ? fooItemWriter : barItemWriter;
        }
    }

}

This prints:

foo writer: item foo
bar writer: item bar


来源:https://stackoverflow.com/questions/62328301/spring-batch-how-to-read-from-one-table-and-write-data-into-two-different-tabl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!