Spring Batch分页读取数据库数据出现重复记录的问题及解决方案
Spring Batch分页读取数据库出现重复数据问题及解决方案
问题现象
使用Spring Batch从数据库读取数据并索引到Solr服务器时,发现Solr中索引的总记录数与数据库完全一致,但存在重复行,并非是写入了新的非法记录,而是部分原有记录被重复写入。
为排除Solr侧问题,将输出目标改为写入CSV文件,问题可复现,确认重复行问题出在数据读取环节。
由于需要读取约2000万行数据,全量读取会导致服务崩溃,因此必须使用分页读取数据库的方案,原始代码片段如下:
@Bean public Step indexingStep() { // @formatter:off return stepBuilder .get("stepOne") .<AddressInfo, AddressInfo> chunk(chunkSize) .reader(addressReader()) .writer(itemWriter()) .build(); // @formatter:on } @Bean public FlatFileItemWriter<AddressInfo> itemWriter() { return new FlatFileItemWriterBuilder<AddressInfo>() .name("personItemWriter") .resource(new FileSystemResource( "data.csv")) .delimited().delimiter(", ") .names(new String[] { "addressDetailPid", "streetLocalityPid", "localityPid"}).build(); } @Bean public ItemReader<AddressInfo> addressReader() { // @formatter:off HibernatePagingItemReader<AddressInfo> hibernatePagingItemReader = new HibernatePagingItemReaderBuilder<AddressInfo>() .name("addReader") .sessionFactory(sessionFactory) .queryString("select f from AddressInfo f") .saveState(false) .pageSize(pageSize) .build(); hibernatePagingItemReader.setUseStatelessSession(true); return hibernatePagingItemReader; // @formatter:on }
问题排查
尝试使用JpaPagingItemReader也出现相同问题,确认是分页机制导致该故障。使用游标式读取器时大多数场景下运行正常,但需要对数据做分区才能避免OOM异常。
运行环境如下:
- jdk11
- Spring Boot 2.4.1
- 数据库:Postgres 9
- Solr:8.1
解决方案
最终确认问题根源是分页查询的JPQL语句没有添加排序规则,导致分页偏移量计算时数据顺序不稳定,部分行在多个分页中被重复读取,在JPQL中添加order by子句即可解决问题,修复后的代码如下:
@Bean public JpaPagingItemReader<AddressInfo> itemReader() { // @formatter:off return new JpaPagingItemReaderBuilder<AddressInfo>() .name("creditReader") .entityManagerFactory(emf) .queryString("select c from AddressInfo c order by c.addressDetailPid ") .pageSize(pageSize) .build(); // @formatter:on }
内容的提问来源于stack exchange,提问作者Mehdi
相关产品推荐
相关产品推荐

