问题
I'm actually using local partitioning to export customer table that has 100K rows to multiple XML files ( as i can't export data to one file because StaxEventItemWriter<T>
isn't Thread-safe) but i don't get better results with multiple Threads even when increasing gridSize
to 10. I think the problem in the StaxEventItemWriter because i have some code errors like :
java.lang.NullPointerException: null
at com.sun.xml.internal.stream.writers.XMLStreamWriterImpl.flush(XMLStreamWriterImpl.java:397) ~[na:1.8.0_121]
at com.sun.xml.internal.stream.writers.XMLEventWriterImpl.flush(XMLEventWriterImpl.java:212) ~[na:1.8.0_121]
at org.springframework.batch.item.xml.StaxEventItemWriter.close(StaxEventItemWriter.java:674) ~[spring-batch-infrastructure-3.0.6.RELEASE.jar:3.0.6.RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_121]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_121]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_121]
at org.springframework.beans.factory.support.DisposableBeanAdapter.invokeCustomDestroyMethod(DisposableBeanAdapter.java:354) [spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:277) [spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.DisposableBeanAdapter.run(DisposableBeanAdapter.java:236) [spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.batch.core.scope.context.StepContext.close(StepContext.java:213) [spring-batch-core-3.0.6.RELEASE.jar:3.0.6.RELEASE]
at org.springframework.batch.core.scope.context.StepSynchronizationManager$1.close(StepSynchronizationManager.java:53) [spring-batch-core-3.0.6.RELEASE.jar:3.0.6.RELEASE]
at org.springframework.batch.core.scope.context.StepSynchronizationManager$1.close(StepSynchronizationManager.java:36) [spring-batch-core-3.0.6.RELEASE.jar:3.0.6.RELEASE]
at org.springframework.batch.core.scope.context.SynchronizationManagerSupport.release(SynchronizationManagerSupport.java:190) [spring-batch-core-3.0.6.RELEASE.jar:3.0.6.RELEASE]
at org.springframework.batch.core.scope.context.StepSynchronizationManager.release(StepSynchronizationManager.java:112) [spring-batch-core-3.0.6.RELEASE.jar:3.0.6.RELEASE]
at org.springframework.batch.core.step.AbstractStep.doExecutionRelease(AbstractStep.java:290) [spring-batch-core-3.0.6.RELEASE.jar:3.0.6.RELEASE]
at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:278) [spring-batch-core-3.0.6.RELEASE.jar:3.0.6.RELEASE]
at org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler$1.call(TaskExecutorPartitionHandler.java:139) [spring-batch-core-3.0.6.RELEASE.jar:3.0.6.RELEASE]
at org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler$1.call(TaskExecutorPartitionHandler.java:136) [spring-batch-core-3.0.6.RELEASE.jar:3.0.6.RELEASE]
Reader
@Bean
@StepScope
public JdbcPagingItemReader<Customer> pagingItemReader(
@Value("#{stepExecutionContext['minValue']}")Long minValue,
@Value("#{stepExecutionContext['maxValue']}")Long maxValue) {
System.out.println("reading " + minValue + " to " + maxValue);
JdbcPagingItemReader<Customer> reader = new JdbcPagingItemReader<>();
reader.setDataSource(this.dataSource);
reader.setFetchSize(10000);
reader.setRowMapper(new CustomerRowMapper());
MySqlPagingQueryProvider queryProvider = new MySqlPagingQueryProvider();
queryProvider.setSelectClause("id, firstName, lastName, birthdate");
queryProvider.setFromClause("from customer");
queryProvider.setWhereClause("where id >= " + minValue + " and id <= " + maxValue);
Map<String, Order> sortKeys = new HashMap<>(1);
sortKeys.put("id", Order.ASCENDING);
queryProvider.setSortKeys(sortKeys);
reader.setQueryProvider(queryProvider);
return reader;
}
Writer
@Bean
@StepScope
public StaxEventItemWriter<Customer> bookItemWriter(
@Value("#{stepExecutionContext['ressource']}")Object ressource
) {
XStreamMarshaller marshaller = new XStreamMarshaller();
StaxEventItemWriter<Customer> itemWriter = new StaxEventItemWriter<>();
itemWriter.setRootTagName("customers");
itemWriter.setMarshaller(marshaller());
File file = new File("C\\resources\\data\\"+ressource+".xml");
String customerOutputPath=file.getAbsolutePath();
itemWriter.setResource(new FileSystemResource(customerOutputPath));
return itemWriter;
}
Partitionner
@Override
public Map<String, ExecutionContext> partition(int gridSize) {
int min = jdbcTemplate.queryForObject("SELECT MIN(" + column + ") from " + table, Integer.class);
int max = jdbcTemplate.queryForObject("SELECT MAX(" + column + ") from " + table, Integer.class);
int targetSize = (max - min) / gridSize + 1;
Map<String, ExecutionContext> result = new HashMap<String, ExecutionContext>();
int number = 0;
int start = min;
int end = start + targetSize - 1;
while (start <= max) {
ExecutionContext value = new ExecutionContext();
result.put("partition" + number, value);
if (end >= max) {
end = max;
}
value.putInt("minValue", start);
value.putInt("maxValue", end);
String partition = "partition" + number;
value.putString("ressource",partition);
start += targetSize;
end += targetSize;
number++;
}
return result;
}}
Thanks for any help.
来源:https://stackoverflow.com/questions/43008684/local-partitioning-in-spring-batch