自定义JdbcPagingItemReader二次迭代参数未设置异常求助
我创建了一个继承JdbcPagingItemReader的类,内部配置如下:
@PostConstruct public void init() throws Exception { setDataSource(dsSrv.getUserDataSource()); setPageSize(Integer.parseInt(pageSize)); setFetchSize(Integer.parseInt(pageSize)); setQueryProvider(queryProvider2(dsSrv.getUserDataSource())); setRowMapper(rowMapper()); }
private PagingQueryProvider queryProvider2(DataSource ds) throws Exception { SqlPagingQueryProviderFactoryBean queryProvider=new SqlPagingQueryProviderFactoryBean(); final Map<String, Order> sortKeys = new HashMap<>(); sortKeys.put("ID", Order.ASCENDING); queryProvider.setDataSource(ds); queryProvider.setSelectClause("*"); queryProvider.setFromClause("D_TABLE"); queryProvider.setWhereClause("ID = '5d7031e6-10f2-4247-b581-17b2fe96449a'"); queryProvider.setSortKeys(sortKeys); return queryProvider.getObject(); }
首次迭代时查询语句符合预期:SELECT TOP 10 * FROM D_TABLE WHERE (ID= '5d7031e6-10f2-4247-b581-17b2fe96449a'),但第二次迭代时生成的查询语句自动添加了AND ((ID > ?))条件,却未设置该参数,抛出如下异常:
org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [SELECT TOP 10 * FROM D_TABLE WHERE (ID = '5d7031e6-10f2-4247-b581-17b2fe96449a') AND ((ID > ?)) ORDER BY ID ASC]; SQL state [null]; error code [0]; The value is not set for the parameter number 1.; nested exception is com.microsoft.sqlserver.jdbc.SQLServerException: The value is not set for the parameter number 1.
解决方案
原因分析
JdbcPagingItemReader的分页逻辑依赖sortKeys定义的字段作为分页游标:每次查询会记录当前页最后一条数据的游标字段值,下一页查询时会自动添加游标字段 > 上一页最后值的条件实现分页。但你的where条件已经固定了唯一ID,第一次查询后无后续数据,分页游标逻辑触发时无法正确绑定参数,从而抛出异常。
解决方法
一次性查询所有数据
由于查询条件仅匹配单条数据,直接将pageSize设置为足够大的值(比如Integer.MAX_VALUE),让JdbcPagingItemReader一次性获取全部结果,避免触发分页迭代:setPageSize(Integer.MAX_VALUE); setFetchSize(Integer.MAX_VALUE);改用JdbcCursorItemReader
如果场景不需要分页,直接使用JdbcCursorItemReader替代JdbcPagingItemReader,它适合一次性读取结果集,无分页游标逻辑:// 示例JdbcCursorItemReader配置 JdbcCursorItemReader<YourEntity> reader = new JdbcCursorItemReader<>(); reader.setDataSource(dsSrv.getUserDataSource()); reader.setSql("SELECT * FROM D_TABLE WHERE ID = '5d7031e6-10f2-4247-b581-17b2fe96449a'"); reader.setRowMapper(rowMapper());调整分页逻辑(不推荐此场景)
若必须保留分页,需确保sortKeys字段未被where条件固定死,同时使用参数化查询绑定条件,让分页游标参数能正确传递。但此场景下分页无实际意义,不建议使用。
内容的提问来源于stack exchange,提问作者thefiery77

