我们做过的很多项目中都会使用spring的JdbcTemplate进行结果集的查询操作,以前在使用的时候一直都是“拿来主义”,功能实现了就OK了,没有深究什么内容,特别是查询接口的回调内容方法,没有过多的研究过细节内容。最近一次使用JdbcTemplate进行查询操作,发现了一些有规律的内容,所以就深入学习了一下。和大家一起探讨一下:
对于spring的JdbcTemplate进行结果集查询操作,spring给我们开发的是一系列的query方法,这些查询的方法中回调的接口主有三种:ResultSetExtractor,RowCallbackHandler,RowMapper,这个内容有图有真相:
一、但是这三种回调接口具体的用法和区别,我们一起来看一下:
场景设定,数据库中存在T_USER表,表中存在多条数据,需要将是表中数据映射到User对象上。
1、org.springframework.jdbc.core.ResultSetExtractor
ResultSetExtractor接口中定义的方法如下:
- public interface ResultSetExtractor {
- Object extractData(ResultSet rs) throws SQLException, DataAccessException;
- }
如果使用ResultSetExtractor接口作为回调方法,查询方式如下:
- List<User> userList = jdbcDao.getJdbcTemplate().
- query("select * from T_USER", new ResultSetExtractor<List<User>>() { //注意这里泛型是List
- @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接口作为回调方法,查询方式如下:
- final List<User> userList = new ArrayList<User>(); //注意在query方法之外
- 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接口中定义的方法如下:
- public interface RowMapper {
- Object mapRow(ResultSet rs, int rowNum) throws SQLException;
- }
如果使用RowMapper接口作为回调方法,查询方式如下:
- List<User> userList = jdbcDao.getJdbcTemplate().
- query("select * from T_USER", new RowMapper<User>(){ //注意这里泛型不是List
- @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接口作为方法的参数:
extractData方法是把ResultSet对应后,需要我们手动迭代封装成List<T>,再返回;(需要我们指定泛型T)- 以RowMapper接口作为方法的参数:
mapRow方法是把ResultSet对应后,结果T会被Spring自动封装成List<T>,再返回;(需要我们指定泛型T)- 以RowCallbackHandler作为方法参数的(这个方法不常用,所以放最后说。和ResultSetExtractor结构很相似):
processRow方法是把ResultSet对应后,也需要我们手动迭代封装成List<T>,但是返回值为void,所以需要我们在query方法外用List<T>来接收processRow中封装的List<T>;2、使用ResultSetExtractor作为Callback接口处理查询结果,我们需要自己声明集合类,自己遍历ResultSet,自己根据每行数据组装Customer对象,自己将组装后的Customer对象添加到集合类中,方法最终只负责将组装完成的集合返回。
对于这三个回调接口的区别,spring的官方文档给出的说明是这样描述的:
写道
ResultSetExtractor
This interface is mainly used within the JDBC framework itself. A RowMapper is usually a simpler choice for ResultSet processing, mapping one result object per row instead of one result object for the entire ResultSet.
Note: In contrast to a RowCallbackHandler, a ResultSetExtractor object is typically stateless and thus reusable, as long as it doesn't access stateful resources (such as output streams when streaming LOB contents) or keep result state within the object.
RowCallbackHandler
In contrast to a ResultSetExtractor, a RowCallbackHandler object is typically stateful: It keeps the result state within the object, to be available for later inspection. SeeRowCountCallbackHandler for a usage example.
Consider using a RowMapper instead if you need to map exactly one result object per row, assembling them into a List.
RowMapper
Typically used either for JdbcTemplate's query methods or for out parameters of stored procedures. RowMapper objects are typically stateless and thus reusable; they are an ideal choice for implementing row-mapping logic in a single place.
Alternatively, consider subclassing MappingSqlQuery from the jdbc.object package: Instead of working with separate JdbcTemplate and RowMapper objects, you can build executable query objects (containing row-mapping logic) in that style.
通过spring的文档描述我们可以知道:
1、RowMapper应该就是一个精简版的ResultSetExtractor,
RowMapper能够直接处理一条结果集内容,
而ResultSetExtractor需要我们自己去ResultSet中去取结果集的内容,
但是ResultSetExtractor拥有更多的控制权,在使用上可以更灵活;
2、与RowCallbackHandler相比,ResultSetExtractor是无状态的,他不能够用来处理有状态的资源。
备注:在spring3中,这三个接口的内容也做出了修改,其中:ResultSetExtractor和RowMapper开始支持泛型,返回值的内容也是泛型中的对象(所以本文我把原文代码修改成泛型的形式了),而RowCallbackHandler没有做出任何修改。
转载自,原文(本文我有修改泛型):https://dzllikelsw-163-com.iteye.com/blog/2038248