JdbcTemplate ResultSetExtractor 执行报异常:No current row in the ResultSet

同一个查询,使用:

1
2
3
List<T> query(String sql, RowMapper<T> rowMapper, Object... args)

void query(String sql, Object[] args, RowCallbackHandler rch)

这两个方法可以执行成功,但是

1
T query(String sql, ResultSetExtractor<T> rse, Object... args)

执行时会报如下异常信息:

1
Caused by: java.sql.SQLException: No current row in the ResultSet.

代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
String sql = "select id, name from user where id = ?";

// 1. RowMapper
List<User> users = jdbcTemplate.query(sql, (rs, rowMap) -> {
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
return user;
}, userId);

// 2. RowCallbackHandler
User user = new User();
jdbcTemplate.query(sql, new Object[]{damId}, rs -> {
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
}, userId);

// 3. ResultSetExtractor
return jdbcTemplate.query(sql, rs -> {
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
return user;
}, userId);

第一种和第二种写法中的 RowMapperRowCallbackHandler 对象分别构造了 RowMapperResultSetExtractor
RowCallbackHandlerResultSetExtractor 对象,它们都是 ResultSetExtractor 的子类。

ResultSetExtractor 类中的 extractData 方法定义为:

1
T extractData(ResultSet rs) throws SQLException, DataAccessException;

RowMapperResultSetExtractor 类定义为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class RowMapperResultSetExtractor<T> implements ResultSetExtractor<List<T>> {

private final RowMapper<T> rowMapper;

private final int rowsExpected;


/**
* Create a new RowMapperResultSetExtractor.
* @param rowMapper the RowMapper which creates an object for each row
*/
public RowMapperResultSetExtractor(RowMapper<T> rowMapper) {
this(rowMapper, 0);
}

/**
* Create a new RowMapperResultSetExtractor.
* @param rowMapper the RowMapper which creates an object for each row
* @param rowsExpected the number of expected rows
* (just used for optimized collection handling)
*/
public RowMapperResultSetExtractor(RowMapper<T> rowMapper, int rowsExpected) {
Assert.notNull(rowMapper, "RowMapper is required");
this.rowMapper = rowMapper;
this.rowsExpected = rowsExpected;
}


@Override
public List<T> extractData(ResultSet rs) throws SQLException {
List<T> results = (this.rowsExpected > 0 ? new ArrayList<T>(this.rowsExpected) : new ArrayList<T>());
int rowNum = 0;
while (rs.next()) {
results.add(this.rowMapper.mapRow(rs, rowNum++));
}
return results;
}

}

第一种写法中形参表里的 lambda 表达式就是 rowMapper 的匿名构造类。

RowCallbackHandlerResultSetExtractor 类定义为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor<Object> {

private final RowCallbackHandler rch;

public RowCallbackHandlerResultSetExtractor(RowCallbackHandler rch) {
this.rch = rch;
}

@Override
public Object extractData(ResultSet rs) throws SQLException {
while (rs.next()) {
this.rch.processRow(rs);
}
return null;
}
}

第二种写法中形参表里的 lambda 表达式就是 rch 的匿名构造类。

所以前两种写法,已经默认执行了循环解析 ResultSet 结果集这个操作。而第三种写法需要自己重写
ResultSetExtractor 类的 extractData() 方法。所以将第三种写法改成以下形式即可:

// ResultSetExtractor
return jdbcTemplate.query(sql, rs -> {
    if (rs.next()) {
        User user = new User();
        user.setId(rs.getInt("id"));
        user.setName(rs.getString("name"));
        return user;
    }
    return null;
}, userId);
分享到:
Disqus 加载中...

如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理