JDBCTemplate的PreparedStatement抛出异常"在结果集开始之前"

时间:2016-03-21 09:08:42

标签: java spring spring-jdbc jdbctemplate

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

+---------------+--------------+------+-----+---------+-------+
| 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 query JDBC Template中使用PreparedStatement? 谢谢。

3 个答案:

答案 0 :(得分:3)

你有一个简单的用例并使用一种更复杂的查询方法,为什么?接下来您使用的是<form:form name="wblCaseType" method="post" modelAttribute="wblCaseType" action="${saveWblCaseType}"> <form:hidden path="wblCaseTypeId" /> <br/> <table style="margin-left:80px"> <tbody> <tr> <td><form:label path="type"><liferay-ui:message key="type"/></form:label></td> <td><form:input path="type" /><form:errors path="type" cssClass="errorClass" /></td> </tr> <tr> <td><form:label path="createRoleIds"><liferay-ui:message key="roles"/></form:label></td> <td><form:checkboxes path="createRoleIds" items="${roles}" value="${wblCaseType.createRoleIds}" itemValue="name" itemLabel="roleId" /></td> </tr> ,而您可能需要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

答案 1 :(得分:3)

您需要将ResultSet#next()调用到&#34;将光标从当前位置向前移动一行。&#34;由于您希望从查询中返回单行,因此可以在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;
}

如果您希望处理多个结果并返回某种类型的集合,那么您将执行while(rs.next())并在循环的每次迭代中处理一行。

另外,在使用JdbcTemplate时,您可以考虑使用RowMapper代替,这可能会略微简化您的实施。

答案 2 :(得分:1)

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

对于您的用例 - 选择给定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;
    });