Spring Batch JdbcPagingItemReader二次运行读取计数为0如何排查
排查步骤与解决方案
- 检查分区器逻辑有效性
在OracleAnIdPartitioner的partition方法中增加日志输出,验证第二次任务运行时是否正确生成了非空的分区集合、每个分区的stepExecutionContext是否正确注入了ANID参数。如果分区器返回空的分区Map,子Step不会执行,读计数自然为0。 - 验证查询Provider的SQL正确性
在A_QueryProviderBean的创建逻辑中增加日志,打印实际获取到的anId值以及最终生成的完整查询SQL,将SQL直接放到Oracle数据库执行确认是否有符合条件的数据。你当前直接拼接字符串到Where子句的写法容易出现语法错误(比如anId值包含特殊字符、空值),也存在SQL注入风险。 - 补充Step允许重复执行配置
同一JobInstance下Spring Batch默认不会重复执行已经标记为完成的Step,即使你关闭了Reader的状态保存也不会触发重新执行。需要给父分区Step和子Step都增加allowStartIfComplete(true)配置,示例如下:@Bean public Step load_A_Step_Partitioned( Step load_A_Step, OracleAnIdPartitioner oracleAnIdPartitioner, TaskExecutor taskExecutor) { return stepBuilderFactory .get("load_A_Step_Partitioned") .partitioner("load_A_Step_Partitioned", oracleAnIdPartitioner) .step(load_A_Step) .gridSize(appConfig.getGridSize()) .taskExecutor(taskExecutor) .allowStartIfComplete(true) // 允许已完成的分区Step重复执行 .build(); } @Bean public Step load_A_Step( JdbcPagingItemReader<SomeDTO> A_Reader, MongoItemWriter<A> writer, A_Processor A_processor) { return stepBuilderFactory .get("load_A") .<SomeDTO, A>chunk(jobConfigCommon.getChunkSize()) .reader(A_Reader) .processor(A_processor) .writer(writer) .allowStartIfComplete(true) // 允许已完成的子Step重复执行 .build(); } - 修正代码拼写错误与SQL注入风险
你当前的A_QueryProvider代码中存在拼写错误:参数注入的数据源是dataSource,但调用providerFactory.setDataSource()时传的是小写开头的datasource,会导致编译报错/数据源注入失败。另外建议将硬拼接的anId改为预编译参数传入,修改示例如下:@Bean @StepScope public PagingQueryProvider A_QueryProvider( @Qualifier("secondaryDatasource") DataSource dataSource) { SqlPagingQueryProviderFactoryBean providerFactory = new SqlPagingQueryProviderFactoryBean(); providerFactory.setDataSource(dataSource); // 修正拼写 providerFactory.setSelectClause("SOME QUERY"); providerFactory.setWhereClause(" anId = :anId "); // 改用参数占位符 providerFactory.setFromClause(" A TABLE "); providerFactory.setSortKey("COLUMN_TO_SORT"); try { return providerFactory.getObject(); } catch (Exception e) { throw new IllegalStateException("Failed to create A_QueryProvider", e); } } @Bean @StepScope public JdbcPagingItemReader<SomeDTO> A_Reader( PagingQueryProvider A_QueryProvider, @Value("#{stepExecutionContext['ANID']}") String anId, // 把anId移到Reader里获取 @Qualifier("secondaryDatasource") DataSource dataSource) { return new JdbcPagingItemReaderBuilder<SomeDTO>() .name("A_Reader") .dataSource(dataSource) .queryProvider(A_QueryProvider) .parameterValues(Collections.singletonMap("anId", anId)) // 传入查询参数 .rowMapper(new A_RowMapper()) .pageSize(jobConfigCommon.getChunkSize()) .saveState(false) .build(); } - 开启 debug 日志确认执行链路
开启org.springframework.batch包的debug日志,确认第二次运行时子Step是否被正常启动、JdbcPagingItemReader是否被正确初始化、执行的查询返回结果数是否为0,快速定位问题出在分区执行链路还是查询逻辑本身。
内容的提问来源于stack exchange,提问作者opensourcegeek
相关产品推荐
相关产品推荐

