我们做过的很多项目中都会使用spring的JdbcTemplate进行结果集的查询操作,以前在使用的时候一直都是“拿来主义”,功能实现了就OK了,没有深究什么内容,特别是查询接口的回调内容方法,没有过多的研究过细节内容。最近一次使用JdbcTemplate进行查询操作,发现了一些有规律的内容,所以就深入学习了一下。和大家一起探讨一下:对于spring的JdbcTemplate进行结果集查询操作,spring给我们开发的是一系列的query方法,这些查询的方法中回调的接口主有三种:ResultSetExtractor,RowCallbackHandler,RowMapper。

但是这三种回调接口具体的用法和区别,我们一起来看一下:

场景设定,数据库中存在T_USER表,表中存在多条数据,需要将是表中数据映射到User对象上

1、org.springframework.jdbc.core.ResultSetExtractor

ResultSetExtractor接口中定义的方法如下:

1
2
3
4
public interface ResultSetExtractor {
Object extractData(ResultSet rs) throws SQLException,
DataAccessException;
}

如果使用ResultSetExtractor接口作为回调方法,查询方式如下:

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
List<User> userList = (List<User>)jdbcDao.getJdbcTemplate().
query("select * from T_USER", new ResultSetExtractor() {
@Override
public Object extractData(ResultSet rs) throws SQLException,
DataAccessException {
List<User> userList = new ArrayList<User>();
while (rs.next()) {
User user = new User();
user.setId(rs.getInt("N_ID"));
user.setName(rs.getString("C_NAME"));
userList.add(user);
}
return userList;
}
});
```
### 2、org.springframework.jdbc.core.RowCallbackHandler
RowCallbackHandler接口中定义的方法如下:
```
public interface RowCallbackHandler {
void processRow(ResultSet rs) throws SQLException;
}

如果使用RowCallbackHandler接口作为回调方法,查询方式如下:

1
2
3
4
5
6
7
8
9
10
11
final List<User> userList = new ArrayList<User>();
jdbcDao.getJdbcTemplate().query("select * from T_USER",
new RowCallbackHandler(){
@Override
public void processRow(ResultSet rs) throws SQLException {
User user = new User();
user.setId(rs.getInt("N_ID"));
user.setName(rs.getString("C_NAME"));
userList.add(user);
}
});

3、org.springframework.jdbc.core.RowMapper

RowMapper接口中定义的方法如下:

1
2
3
public interface RowMapper {
Object mapRow(ResultSet rs, int rowNum) throws SQLException;
}

如果使用RowMapper接口作为回调方法,查询方式如下:

1
2
3
4
5
6
7
8
9
10
11
List<User> userList = (List<User>)jdbcDao.getJdbcTemplate().
query("select * from T_USER", new RowMapper(){
@Override
public Object mapRow(ResultSet rs, int rowNumber)
throws SQLException {
User user = new User();
user.setId(rs.getInt("N_ID"));
user.setName(rs.getString("C_NAME"));
return user;
}
});

通过以上的例子我们可以看出,使用三种回调接口主要的区别是:

1、使用三种Callback接口作为参数的query方法的返回值不同:

以ResultSetExtractor作为方法参数的query方法返回Object型结果,要使用查询结果,我们需要对其进行强制转型;

以RowMapper接口作为方法参数的query方法直接返回List型的结果;

以RowCallbackHandler作为方法参数的query方法,返回值为void;

2、使用ResultSetExtractor作为Callback接口处理查询结果,我们需要自己声明集合类,自己遍历ResultSet,自己根据每行数据组装Customer对象,自己将组装后的Customer对象添加到集合类中,方法最终只负责将组装完成的集合返回。

通过spring的文档描述我们可以知道:

1、RowMapper应该就是一个精简版的ResultSetExtractor,RowMapper能够直接处理一条结果集内容,而ResultSetExtractor需要我们自己去ResultSet中去取结果集的内容,但是ResultSetExtractor拥有更多的控制权,在使用上可以更灵活;

2、与RowCallbackHandler相比,ResultSetExtractor是无状态的,他不能够用来处理有状态的资源。

备注:在spring3中,这三个接口的内容也做出了修改,其中:ResultSetExtractor和RowMapper开始支持泛型,返回值的内容也是泛型中的对象,而RowCallbackHandler没有做出任何修改。