带有 sortKeys 和参数值的 Spring Batch Paging
Posted
技术标签:
【中文标题】带有 sortKeys 和参数值的 Spring Batch Paging【英文标题】:Spring Batch Paging with sortKeys and parameter values 【发布时间】:2015-01-18 21:54:52 【问题描述】:我有一个在 Spring Boot 中运行的 Spring Batch 项目,它运行良好。对于我的读者,我将 JdbcPagingItemReader 与 mysqlPagingQueryProvider 一起使用。
@Bean
public ItemReader<Person> reader(DataSource dataSource)
MySqlPagingQueryProvider provider = new MySqlPagingQueryProvider()
provider.setSelectClause(ScoringConstants.SCORING_SELECT_STATEMENT)
provider.setFromClause(ScoringConstants.SCORING_FROM_CLAUSE)
provider.setSortKeys("p.id": Order.ASCENDING)
JdbcPagingItemReader<Person> reader = new JdbcPagingItemReader<Person>()
reader.setRowMapper(new PersonRowMapper())
reader.setDataSource(dataSource)
reader.setQueryProvider(provider)
//Setting these caused the exception
reader.setParameterValues(
startDate: new Date() - 31,
endDate: new Date()
)
reader.afterPropertiesSet()
return reader
但是,当我使用一些命名参数修改我的查询以替换以前硬编码的日期值并在阅读器上设置这些参数值时,如上所示,我在 second 页面读取时收到以下异常(第一页可以正常工作,因为分页查询提供程序没有使用 _id 参数):
org.springframework.dao.InvalidDataAccessApiUsageException: No value supplied for the SQL parameter '_id': No value registered for key '_id'
at org.springframework.jdbc.core.namedparam.NamedParameterUtils.buildValueArray(NamedParameterUtils.java:336)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.getPreparedStatementCreator(NamedParameterJdbcTemplate.java:374)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:192)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:199)
at org.springframework.batch.item.database.JdbcPagingItemReader.doReadPage(JdbcPagingItemReader.java:218)
at org.springframework.batch.item.database.AbstractPagingItemReader.doRead(AbstractPagingItemReader.java:108)
这里是一个 SQL 的例子,它默认没有 WHERE 子句。读取第二页时会自动创建一个:
select *, (select id from family f where date_created between :startDate and :endDate and f.creator_id = p.id) from person p
在第二页,sql被修改为以下,但是似乎没有提供_id的命名参数:
select *, (select id from family f where date_created between :startDate and :endDate and f.creator_id = p.id) from person p WHERE id > :_id
我想知道我是否不能将 MySqlPagingQueryProvider 排序键与 JdbcPagingItemReader 中设置的其他命名参数一起使用。如果不是,解决这个问题的最佳选择是什么?我需要能够为查询提供参数并对其进行分页(与使用光标相比)。谢谢!
【问题讨论】:
您似乎没有为新值设置 where 子句。您的配置示例中是否缺少此内容? @MichaelMinella 感谢您的帮助。我在上面提供了一些 SQL。我的初始查询中没有 WHERE 子句,但是分页提供程序会在第一页之后自动添加一个。 我的意思是当你配置你的提供者时,你没有为 startDate 和 endDate 设置 where 子句,还是我遗漏了什么? @MichaelMinella,请注意,这些不是在 where 子句中使用,而是在子选择中使用。您是否认为出于某种原因这会导致我在 _id 字段中遇到问题?我意识到我可以将其更改为连接而不是子选择并使用 where 子句,但我有许多额外的子选择不能成为连接,我为了减少混淆而删除了这些选择。该查询经过测试并且有效。就像我说的,第 1 页运行良好,直到第 2 页自动添加 WHERE 子句,命名的 _id 参数才被绑定。再次感谢您! 查看source 以及getParameterMap 函数的工作原理,它似乎涵盖了它。您是否有机会打开日志记录并查看“使用参数映射”的输出? 【参考方案1】:我通过一些密集的调试解决了这个问题。事实证明,MySqlPagingQueryProvider 在构建 SQL 查询以针对第一页和后续页面运行时使用了 getSortKeysWithoutAliases()
方法。因此它附加了and (p.id > :_id)
而不是and (p.id > :_p.id)
。稍后,当创建第二个页面排序值并将其存储在 JdbcPagingItemReader 的startAfterValues
字段中时,它将使用指定的原始"p.id"
字符串并最终将("_p.id",10)
对放入命名参数映射中。但是,当阅读器尝试在查询中填写_id时,它并不存在,因为阅读器使用了非别名删除键。
长话短说,我在定义排序键时必须删除别名引用。
provider.setSortKeys("p.id": Order.ASCENDING)
为了让一切都能很好地协同工作,必须更改为
provider.setSortKeys("id": Order.ASCENDING)
【讨论】:
【参考方案2】:我遇到了同样的问题并得到了另一个可能的解决方案。
我的表 T 有一个主键字段 INTERNAL_ID。
JdbcPagingItemReader 中的查询是这样的:
SELECT INTERNAL_ID, ... FROM T WHERE ... ORDER BY INTERNAL_ID ASC
所以,关键是:在某些情况下,查询没有返回结果,然后,引发上述错误没有为...提供值
解决办法是:
如果有行,请签入 Spring Batch decider 元素。 如果是,继续块:reader-processor-writer。 不是这样,继续下一步。请注意,它们是两种不同的场景:
开头是行。您通过分页获得它们,最后,没有更多的行了。这没有问题,不需要决策技巧。 开始时没有行。然后,出现了这个错误,决策者解决了它。希望这会有所帮助。
【讨论】:
以上是关于带有 sortKeys 和参数值的 Spring Batch Paging的主要内容,如果未能解决你的问题,请参考以下文章
带有属性值的 RequestMapping 的 Spring Boot REST 控制器测试
iis urlrewrite HTTPS,除了服务(.asmx 和 .svc)或带有参数/值的特定服务