Spring JDBC中RowMapper与ResultSetExtractor差异及RowMapper异常排查
问题根因
- RowMapper实现不符合接口规范
RowMapper<T>的泛型参数T代表你需要把数据库行映射成的目标业务对象类型,你代码里直接把RowMapper实现类ModelRowMapper作为泛型参数,完全不符合接口设计逻辑。同时你贴出的mapRow方法没有按接口要求返回映射后的对象,编译阶段就会报错,即便你实际代码补了返回语句,错误的类型设计也会导致结果异常。 - API使用不匹配
你要查询的是单条记录,却用了设计用来返回结果列表的jdbcTemplate.query()方法。该方法会自动遍历ResultSet的所有行,每一行调用一次mapRow。如果你的mapRow方法内部误操作了ResultSet游标(比如自行调用rs.next()、rs.first()这类移动游标的方法),就会导致Spring的外层遍历逻辑读取到无效的游标位置,出现多次打印、最终返回无效值的问题。
而ResultSetExtractor是由开发者自己控制ResultSet的遍历逻辑,你没有额外操作游标所以运行正常。 - (可选)SQL执行结果不符合预期
可以先直接在数据库客户端执行对应SQL,确认确实只返回1行数据,排除SQL语法错误导致返回多条数据的可能。
解决建议
- 修正RowMapper实现
把泛型参数换成你实际需要映射的业务实体类,mapRow内不要调用任何移动ResultSet游标的方法,只需要从当前行取值填充对象后返回即可,示例如下:
// 假设你的业务实体类为Model public class ModelRowMapper implements RowMapper<Model> { @Override public Model mapRow(ResultSet rs, int rowNum) throws SQLException { Model model = new Model(); model.setValue(rs.getString("value")); // 其他字段赋值逻辑 return model; } }
- 改用匹配需求的JdbcTemplate方法
查询单条记录时使用queryForObject而非query方法:
public void test(){ String sql = "SELECT value FROM 你的表名 WHERE dateColumn <= '2021-08-17' LIMIT 1"; Model result = jdbcTemplate.queryForObject(sql, new ModelRowMapper()); // 输出预期结果2021-08-15 System.out.println(result.getValue()); }
- 校验SQL正确性
如果修改后还有问题,直接在数据库执行SQL确认返回结果行数,排除SQL书写错误的干扰。
内容的提问来源于stack exchange,提问作者vivek
相关产品推荐
相关产品推荐

