问题
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