取回数据时的批量提示,与最终允许返回多少行,是两种配置。商户工具的结果上限需要明确实施,完整性还需要独立的分页或截断契约。
前置:列表分页与稳定排序。以下代码片段与数据库对照未编译、未运行。
两层 API 的默认值
JDBC fetchSize是驱动获取后续结果时的行数提示,不是整个查询最多返回多少行;驱动是否以及如何采用提示,不能凭配置值推定。Statement.setMaxRows限制ResultSet最多包含的行数,超过部分会被静默丢弃,0表示不设上限。JdbcTemplate两项默认值都是-1,表示不向驱动传入特定设置;不要把Spring的-1与JDBC的0混成同一层API约定。配置完成的JdbcTemplate才具备文档所述线程安全用法,不为每个并发请求临时修改共享模板参数。
若商户工具承诺最多返回20条,不能仅设fetchSize(20)就认为响应有界;反之,收到恰好20条也不能据此断言全量只有20家。maxRows截断没有额外一条可用于证明是否还有下一页,应结合既有分页契约显式保留完整性状态。本节只补JDBC参数语义,不替代SQL排序、授权过滤、分页设计,也不承诺限制数据库扫描量或网络往返次数。
固定七行的最小对照
在隔离测试中给当前租户准备恰好7行、其他租户若干行,确保id非空且唯一。tenantId来自已认证服务端上下文;用每条PreparedStatement设置参数,不改共享JdbcTemplate。以下是测试辅助方法,不是生产工具直接开放maxRows输入。
这里假定 JdbcTemplate 的 maxRows 保持默认 -1,额外上限只在本次 PreparedStatement 上设置;若模板另有结果截断,必须一并纳入断言。
static List<Long> ids(JdbcTemplate jdbc, long tenantId, int maxRows) {
return jdbc.query(
"SELECT id FROM shop WHERE tenant_id = ? ORDER BY id",
ps -> {
ps.setLong(1, tenantId);
ps.setFetchSize(2); // 抓取提示,不是结果总数
ps.setMaxRows(maxRows);
},
(rs, rowNum) -> rs.getLong("id"));
}
// 在固定7行夹具中分别验收:
// ids(jdbc, tenantId, 0) 的ID集合为全部7行;
// ids(jdbc, tenantId, 3) 为按id排序的前3行。
练习 行数与完整性分别验收
第一组保持SQL、租户与数据不变,对比fetchSize=2而maxRows=0的7行结果,与maxRows=3的3行结果;记录实际驱动/数据库版本、返回ID和异常,不把fetchSize调用次数当数据库往返次数。第二组分别准备恰好3行与7行,两组都设maxRows=3;虽然都返回3行,底层匹配总数不同。断言工具不得只凭结果长度宣称“全部列完”,若业务要求hasMore则按项目既有明确方案另验,不从静默截断猜测。
验收范围
本节不测量内存、数据库扫描量、网络往返次数或驱动是否实际分批抓取,也不据此建议生产参数。原有授权范围、唯一排序、分页与工具部分完成契约继续生效;实际数据库、驱动及 Spring 版本必须写进运行记录。
来源与版本
Spring Framework 7.0.10 与 OpenJDK jdk-21+35。资料原核查时间为 2026 年 10 月 29 日 00:07 JST;独立发布日期未核实。来源:JdbcTemplate setFetchSize 及同页 setMaxRows、Statement 固定标签源码。