当我做一个简单的批处理时,遇到了一个问题,该批处理从postgresql数据库中读取数据,处理并写入一个csv文件。以下是读者:
@Bean
@StepScope
public ItemReader<SearchResult> databaseReader(@Qualifier("reportingDataSource") HikariDataSource reportDataSource,
@Value("#{stepExecution}") StepExecution stepExecution) {
JdbcPagingItemReader<SearchResult> reader = new JdbcPagingItemReader<>();
reader.setQueryProvider(createQueryProvider());
reader.setRowMapper(new CustomRowMapper());
reader.setDataSource(reportDataSource);
reader.setPageSize(5);
reader.open(stepExecution.getExecutionContext());
return reader;
}
private PagingQueryProvider createQueryProvider(SearchTxnRequest searchTxnRequest) {
SqlitePagingQueryProvider queryProvider = new SqlitePagingQueryProvider();
queryProvider.setSelectClause("SELECT *");
queryProvider.setFromClause("from dummy_table");
queryProvider.setSortKeys(sortBy());
return queryProvider;
}
private Map<String, Order> sortBy() {
Map<String, Order> sortConfiguration = new HashMap<>();
sortConfiguration.put("date", Order.ASCENDING);
return sortConfiguration;
}
我将虚拟数据插入具有不同ID的'dummy_table'中,但在其他字段(包括日期字段)中使用了相同的数据。正如您在代码中看到的那样,sortBy函数定义了对表中信息进行排序的方式,我只选择了日期字段。问题出现在这里,如果表中的所有行都有相同的日期,则批处理仅返回前5行(如果页面大小为5)。
为什么?好吧,JdbcPagingItemReader使用排序键(在这种情况下仅是日期)进行分页。调试显示以下内容:因此,阅读第一页
2020-03-30 15:01:40 DEBUG [nio-7035-exec-1] o.s.b.i.database.JdbcPagingItemReader : Reading page 0
2020-03-30 15:01:40 DEBUG [nio-7035-exec-1] o.s.b.i.database.JdbcPagingItemReader : SQL used for reading first page: [SELECT * FROM from dummy_table ORDER BY date ASC LIMIT 5]
第二页:
2020-03-30 15:01:40 [nio-7035-exec-1] o.s.b.i.database.JdbcPagingItemReader : Reading page 1
2020-03-30 15:01:40 [nio-7035-exec-1] o.s.b.i.database.JdbcPagingItemReader : SQL used for reading remaining pages: [SELECT * FROM from dummy_table WHERE ((date > ?)) ORDER BY date ASC LIMIT 5]
您可以看到,分页是由日期排序键完成的。我的问题是表中的所有数据都具有相同的日期。重要的是,明智地选择排序键,以避免出现分页问题。我添加了ID,就可以解决问题。
[您不需要在reader.open
方法中调用databaseReader
,如果您的阅读器被声明为ItemStreamReader
,则Spring Batch将执行此操作。我建议在读取器/写入器bean定义中返回最特定的类型,以便Spring Batch可以正确创建代理。您的情况应该是这样的:
@Bean
@StepScope
public JdbcPagingItemReader<SearchResult> databaseReader(@Qualifier("reportingDataSource") HikariDataSource reportDataSource) {
JdbcPagingItemReader<SearchResult> reader = new JdbcPagingItemReader<>();
reader.setQueryProvider(createQueryProvider());
reader.setRowMapper(new CustomRowMapper());
reader.setDataSource(reportDataSource);
reader.setPageSize(5);
return reader;
}
重要的是,明智地选择排序键,以避免出现分页问题。我添加了ID,就可以解决问题。
是的,正如所记录的,这是JdbcPagingItemReader和AbstractSqlPagingQueryProvider的Javadocs的摘录:
It is important to have a unique key constraint on the sort key
The columns that make up the sort key must be a true key and not just a column to order by
我相信您的日期列不是键,这就是为什么添加ID时起作用的原因。