Spring Batch多线程步骤中JdbcPagingItemReader无数据时排序键报错及setSaveState作用
问题
使用Spring Batch 4.3.5开发批处理应用,在多线程步骤中使用JdbcPagingItemReader时,当查询无数据会触发如下错误:
org.springframework.dao.InvalidDataAccessApiUsageException: No value supplied for the SQL parameter '_PIN_SEQ_ID': No value registered for key '_PIN_SEQ_ID' at org.springframework.jdbc.core.namedparam.NamedParameterUtils.buildValueArray(NamedParameterUtils.java:354) at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.getPreparedStatementCreator(NamedParameterJdbcTemplate.java:418) at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.getPreparedStatementCreator(NamedParameterJdbcTemplate.java:392)
Reader代码如下,添加reader.setSaveState(false)前会触发上述错误:
public JdbcPagingItemReader<BatchUserHistoryMVDO> processJobReader( @Value("#{jobExecutionContext[batchId]}") long batchId) { final JdbcPagingItemReader<BatchUserHistoryMVDO> reader = new JdbcPagingItemReader<>(); final BatchUserHistoryMVMapper userHistoryMVMapper = new BatchUserHistoryMVMapper(); reader.setDataSource(this.dataSource.getSecondaryDataSource()); reader.setFetchSize(this.configProperties.getProcessPageSize()); reader.setPageSize(this.configProperties.getProcessPageSize()); reader.setRowMapper(userHistoryMVMapper); reader.setQueryProvider(createQuery()); Map<String, Object> parameters = new HashMap<>(); parameters.put("id", batchId); reader.setParameterValues(parameters); return reader; } private AbstractSqlPagingQueryProvider createQuery() { final Map<String, Order> sortKeys = new HashMap<>(); sortKeys.put("PIN_SEQ_ID", Order.ASCENDING); final AbstractSqlPagingQueryProvider queryProvider = new OraclePagingQueryProvider(); queryProvider.setSelectClause("*"); queryProvider.setFromClause("from POA01.BATCH_USER_HISTORY_MV where batch_id = :id"); queryProvider.setSortKeys(sortKeys); return queryProvider; }
添加reader.setSaveState(false)后批处理可正常完成,请问该方法在此场景中起到什么作用?未设置时为何会因排序键导致报错?
解答
setSaveState(false)的作用
- 关闭ItemReader的状态持久化:Spring Batch默认会将ItemReader的读取状态(比如分页查询的当前位置、排序键的最后取值等)保存到Job Execution Context,用于任务重启时恢复读取进度。设置
setSaveState(false)后,Reader不再保存或恢复任何状态,每次运行都从头开始读取。 - 规避多线程状态冲突:在多线程步骤中,多个Reader实例会共享同一Job Execution Context的状态,关闭状态持久化后,每个线程的Reader独立运行,不会互相干扰。
未设置时报错的原因
当查询无数据时,JdbcPagingItemReader第一次执行查询返回空结果集,但因为默认开启状态保存(saveState=true),它会尝试将排序键PIN_SEQ_ID的"最后取值"保存到上下文。由于没有数据,这个排序键没有对应的取值,后续Spring Batch在处理状态时,错误地将排序键当作SQL参数(自动添加前缀_变成_PIN_SEQ_ID)去查找参数值,但你仅设置了:id参数,没有_PIN_SEQ_ID的参数值,因此触发InvalidDataAccessApiUsageException。
简单来说,空结果集导致状态保存逻辑异常,把排序键误判为未提供的SQL参数,关闭状态保存后就不会触发这个异常流程了。
内容的提问来源于stack exchange,提问作者tzaman3
相关产品推荐
相关产品推荐

