JDBCTemplate 的 PreparedStatement 抛出异常 "Before start of result set"

PreparedStatement of JDBCTemplate throws exception "Before start of result set"

我正在使用 Spring JdbcTemplate。我有查询通过 ID 获取数据。 我有这个 table 模式:

+---------------+--------------+------+-----+---------+-------+
| Field         | Type         | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+-------+
| id            | varchar(150) | NO   | PRI | NULL    |       |
| position_name | varchar(150) | NO   |     | NULL    |       |
| description   | text         | YES  |     | NULL    |       |
+---------------+--------------+------+-----+---------+-------+

我 运行 使用此模板:

public Position fetchById(final String id) throws Exception {
    // TODO Auto-generated method stub
    String sql = "SELECT * FROM position WHERE id = ?";

    return jdbcTemplate.query(sql, new PreparedStatementSetter() {
        public void setValues(PreparedStatement ps) throws SQLException {
            // TODO Auto-generated method stub
            ps.setString(1, id);
        }
    }, new ResultSetExtractor<Position>() {

        public Position extractData(ResultSet rs) throws SQLException,
                DataAccessException {
            // TODO Auto-generated method stub
            Position p = new Position();
            p.setId(rs.getString("id"));
            p.setPositionName(rs.getString("position_name"));
            p.setDescription(rs.getString("description"));

            return p;
        }
    });
}

但是当我 运行 像这样进行单元测试时:

@Test
public void getPositionByIdTest() throws Exception {
    String id = "35910510-ef2f-11e5-9ce9-5e5517507c66";
    Position p = positionService.getPositionById(id);

    Assert.assertNotNull(p);
    Assert.assertEquals("Project Manager", p.getPositionName());
}

我收到以下错误:

org.springframework.dao.TransientDataAccessResourceException: PreparedStatementCallback; SQL [SELECT * FROM position WHERE id = ?]; Before start of result set; nested exception is java.sql.SQLException: Before start of result set
    at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:108)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
    ...
Caused by: java.sql.SQLException: Before start of result set
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:896)
    ...

如何在Select查询JDBC模板中使用PreparedStatement? 谢谢。

您有一个简单的用例并使用了一种更复杂的查询方法,为什么?接下来您使用的是 ResultSetExtractor 而您可能需要 RowMapper 来代替。如果你使用 ResultSetExtractor 你将不得不自己迭代结果集。用以下

替换您的代码
return getJdbcTemplate.query(sql, new RowMapper<Position>() {
    public Position mapRow(ResultSet rs, int row) throws SQLException,
            DataAccessException {
        Position p = new Position();
        p.setId(rs.getString("id"));
        p.setPositionName(rs.getString("position_name"));
        p.setDescription(rs.getString("description"));

        return p;
    }, id);
} 

因此,与其使用一种更复杂的方法,不如使用一种适合您需要的方法。 JdbcTemplate 无论如何都使用 PreparedStatement

您需要调用 ResultSet#next() 到 "move the cursor forward one row from its current position." 由于您希望从查询中 return 编辑单行,因此您可以在 if 中调用它声明如下:

public Position extractData(ResultSet rs) throws SQLException,
            DataAccessException {
        Position p = new Position();
        if(rs.next()) {
            p.setId(rs.getString("id"));
            p.setPositionName(rs.getString("position_name"));
            p.setDescription(rs.getString("description"));
        }
        return p;
}

如果您希望处理多个结果和 return 某种集合,您可以 while(rs.next()) 并在循环的每次迭代中处理一行。

此外,当您使用 JdbcTemplate 时,您可以考虑使用 RowMapper,这可能会稍微简化您的实施。

如果您使用 ResultSetExtractor,则必须遍历使用 next() 调用的结果。这解释了错误,因为当您读取其值时 ResultSet 仍位于第一行之前。

对于您的用例 - select 给定 ID 的记录 - 使用 JdbcTemplate.queryForObjectRowMapper lambda 有一个更简单的解决方案:

String sql = "SELECT * FROM position WHERE id = ?";
Position position = (Position) jdbcTemplate.queryForObject(
    sql, new Object[] { id }, (ResultSet rs, int rowNum)  -> {
        Position p = new Position();
        p.setId(rs.getString("id"));
        p.setPositionName(rs.getString("position_name"));
        p.setDescription(rs.getString("description"));
       r eturn p;
    });