SQL Serverからデータを読み取り、ファイルに書き込むSpringバッチプロセスがあります。私が使用しているクエリは350000行を返し、SQL Serverスタジオでの実行に約2分かかるため、クエリは最高のパフォーマンスが得られるように調整されています。
以下はJobConfigurationクラスです:
@Configuration
@Slf4j
public class JobConfiguration {
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
private final FileProperties fileProperties;
private JobProperties jobProperties;
private FileUtility fileUtility;
private CompensationDetailStatusRepository compensationDetailStatusRepository;
private CompensationDetailsRepository compensationDetailsRepository;
@Autowired
public JobConfiguration(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory,
JobProperties jobProperties, FileProperties fileProperties
) {
this.jobBuilderFactory = jobBuilderFactory;
this.stepBuilderFactory = stepBuilderFactory;
this.jobProperties = jobProperties;
this.fileProperties = fileProperties;
}
@Bean
public Job processExtractJob(ExtractProcessListener listener,
Step processExtract,
Step moveFiles
) {
return jobBuilderFactory.get("processExtractJob")
.incrementer(new RunIdIncrementer())
.listener(listener)
.start(processExtract)
.on("COMPLETED")
.to(moveFiles)
.end()
.build();
}
@Bean
public Step processExtract(ItemReader<Person> PersonReader,
ExtractProcessor extractProcessor,
ExtractWriter extractWriter
) {
return stepBuilderFactory.get("processExtract")
.<Person, ExtractVO>chunk(50)
.faultTolerant()
.retryLimit(1)
.retry(IOException.class)
.retry(UncheckedIOException.class)
.reader(PersonReader)
.processor(extractProcessor)
.writer(extractWriter)
.build();
}
@Bean
public ExtractWriter extractWriter() {
return new ExtractWriter();
}
@Bean
public ExtractProcessor extractProcessor() {
return new ExtractProcessor();
}
@Bean
public Step moveFiles() {
return stepBuilderFactory.get("moveFiles")
.tasklet((contribution, chunkContext) -> {
fileUtility.moveFiles(String.format("%s*", fileProperties.getFileNamePrefix()),
fileProperties.getFileStagingPath(), fileProperties.getFileTargetPath());
return RepeatStatus.FINISHED;
}).build();
}
@Bean
@StepScope
public ItemReader<Person> PersonReader(EntityManagerFactory entityManagerFactory) {
String query = "Select new com.example.Person (DTL.personId,DTL.description) FROM DETAIL DTL;";
JpaPagingItemReader<Person> reader = new JpaPagingItemReader<>();
reader.setQueryString(query);
reader.setTransacted(false);
reader.setPageSize(jobProperties.getReaderPageSize());
reader.setEntityManagerFactory(entityManagerFactory);
reader.setPageSize(jobProperties.getReaderPageSize());
return reader;
}
@Bean
public ExtractProcessListener jobExecutionListener() {
return new ExtractProcessListener();
}
}
以下は、データベース結果セットのjavaオブジェクト(Person.java)です。
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Data
public class PersonCompensation {
private String personId;
private String description;
}
バッチプロセスを実行すると、次の例外が発生します。
2020-04-15 21:34:59.172 ERROR 11748 --- [rTaskExecutor-1] o.s.batch.core.step.AbstractStep : Encountered an error executing step processExtract in job processExtractJob
org.springframework.batch.core.step.skip.NonSkippableReadException: Non-skippable exception during read
at org.springframework.batch.core.step.item.FaultTolerantChunkProvider.read(FaultTolerantChunkProvider.java:105) ~[spring-batch-core-3.0.8.RELEASE.jar:3.0.8.RELEASE]
at org.springframework.batch...
Caused by: java.lang.NullPointerException: null
at org.springframework.batch.item.database.JpaPagingItemReader.doReadPage(JpaPagingItemReader.java:196) ~[spring-batch-infrastructure-3.0.8.RELEASE.jar:3.0.8.RELEASE]
at org.springframework.batch.item.database.AbstractPagingItemReader.doRead(AbstractPagingItemReader.java:108) ~[spring-batch-infrastructure-3.0.8.RELEASE.jar:3.0.8.RELEASE]
at org.springframework.batch.item.support...
... 27 common frames omitted
2020-04-15 21:34:59.946 WARN 11748 --- [rTaskExecutor-1] o.s.b.f.support.DisposableBeanAdapter : Invocation of destroy method 'close' failed on bean with name 'scopedTarget.personCompensationReader': org.springframework.batch.item.ItemStreamException: Error while closing item reader
2020-04-15 21:35:00.277 ERROR 11748 --- [rTaskExecutor-1] o.s.batch.core.job.AbstractJob : Encountered fatal error executing job
org.springframework.batch.core.JobExecutionException: Flow execution ended unexpectedly
at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:140) ~[spring-batch-core-3.0.8.RELEASE.jar:3.0.8.RELEASE]
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:306) ~[spring-batch-core-3.0.8.RELEASE.jar:3.0.8.RELEASE]
at org.springframework.batch.core...
Caused by: org.springframework.batch.core.job.flow.FlowExecutionException: Next state not found in flow=processExtractJob for state=processExtractJob.processExtract with exit status=FAILED
at org.springframework.batch.core.job.flow.support.SimpleFlow.nextState(SimpleFlow.java:230) ~[spring-batch-core-3.0.8.RELEASE.jar:3.0.8.RELEASE]
at org.springframework.batch.core...
Exit Code: FAILED
Exit Desc: org.springframework.batch.core.step.skip.NonSkippableReadException: Non-skippable exception during read
at org.springframework.batch.core.step.item.FaultTolerantChunkProvider.read(FaultTolerantChunkProvider.java:105)
at org.springframework.batch.core.step.item.SimpleChunkProvider$1.doInIteration(SimpleChunkProvider.java:116)
at org.springframework.batch...
Caused by: java.lang.NullPointerException
at org.springframework.batch.item.database.JpaPagingItemReader.doReadPage(JpaPagingItemReader.java:196)
at org.springframework.batch.item.database.AbstractPagingItemReader.doRead(AbstractPagingItemReader.java:108)
at org.springframework.batch.item...
... 27 more
3つの質問があります。
JpaPagingItemReader<Person> reader = new JpaPagingItemReader<>();
。Personクラスは、これが機能するためのEntityオブジェクトにする必要がありますか、それともPOJOは正常に機能しますか?
- Springバッチは350000行すべてを一度にクエリしてフェッチし、50(チャンクサイズ)のチャンクでレコードをプロセッサに渡しますか?
いいえ、pageSize
一度にすべてのアイテムではなくアイテムのみを読み取ります(ページングリーダーのポイントです)。ChunkSizeとPageSizeは異なるパラメーターです。たとえば、100アイテムのページを読み取り、各ページに10アイテムのチャンクを10個持つことができます。通常、pageSizeとchunkSizeを一致させると、パフォーマンスが向上します。Javadocを参照してください。
- コードJpaPagingItemReader reader = new JpaPagingItemReader <>();にこの行があります。Personクラスは、これが機能するためのEntityオブジェクトにする必要がありますか、それともPOJOは正常に機能しますか?
はい、そうでなければJPAリーダーを使用する目的がわかりません(JDBCリーダーで十分です)。
- 上記の例外の原因は何ですか?
ここにNullPointerExceptionがあります。これは、エンティティマネージャーがであることを意味しますnull
。afterPropertiesSet
リーダーが正しく構成されていることを確認するには、リーダーを呼び出す必要があります。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加