JdbcTemplate针对数据查询提供了多个重载的模板方法,你可以根据需要选用不同的模板方法。如果你的查询很简单,仅仅是传入相应SQL或者相关参数,然后取得一个单一的结果,那么你可以选择如下一组便利的模板方法:

intqueryForInt(Stringsql)

intqueryForInt(Stringsql,Object[]args)

longqueryForLong(Stringsql)

longqueryForLong(Stringsql,Object[]args)

ObjectqueryForObject(Stringsql,Cla***equiredType)

ObjectqueryForObject(Stringsql,Object[]args,Cla***equiredType)

MapqueryForMap(Stringsql)

MapqueryForMap(Stringsql,Object[]args)

比如说,你所查询的结果就包含一列数字型的结果,或者使用了SQL函数,或者其他单列的结果,我们就可以直接通过这组便利的模板方法进行查询:
intage=jdbcTemplate.queryForInt("selectagefromcustomerwherecustomerId=?",newObject[]{newInteger(100)});
...
longinterval=jdbcTemplate.queryForLong("selectcount(customerId)fromcustomer");
...
StringcustomerName=jdbcTemplate.queryForString("selectusernamefromcustomerwherecustomerId=110");
...
MapsingleCustomer=jdbcTemplate.queryForMap("select*fromcustomerlimit1");
...
queryForMap方法与其他方法不同之处在于,它的查询结果以java.util.Map的形式返回,Map的key对应所查询表的列名,Map的value当然就是对应key所在列的值啦。当然了,你也看到了,这组模板方法主要用于单一结果的查询,使用的时候也请确保你的SQL查询所返回的结果是单一的,否则,JdbcTemplate将抛出org.springframework.dao.IncorrectResultSizeDataAccessException异常。
如果查询的结果将返回多行,而你又不在乎他们是否拥有较强的类型约束,那么,以下模板方法可以帮助你:

ListqueryForList(Stringsql)

ListqueryForList(Stringsql,Object[]args)

queryForList方法根据传入的SQL以及相应的参数执行查询,将查询的结果以java.util.List的形式返回,返回的java.util.List中的每一个元素都是java.util.Map类型,分别对应结果集中的一行,Map的Key为每一列的列名,而Map的值就是当前行列名对应的值。
好啦,如果这些还不足以满足你的查询需要,那么我们就更进一步,使用相应的Callback接口对查询结果的返回进行定制吧!

用于查询的回调接口定义主要有以下三种:

org.springframework.jdbc.core.ResultSetExtractor.基本上属于JdbcTemplate内部使用的Callback接口,相对于下面两个Callback接口来说,ResultSetExtractor拥有更多的控制权,因为使用它,你需要自行处理ResultSet:

publicinterfaceResultSetExtractor
{
ObjectextractData(ResultSetrs)throwsSQLException,DataAccessException;
}
在直接处理完ResultSet之后,你可以将处理后的结果以任何你想要的形式包装后返回。
org.springframework.jdbc.core.RowCallbackHandler.RowCallbackHandler相对于ResultSetExtractor来说,仅仅关注单行结果的处理,处理后的结果可以根据需要存放到当前RowCallbackHandler对象内或者使用JdbcTemplate的程序上下文中,当然,这个完全是看个人爱好了。RowCallbackHandler的定义如下:

publicinterfaceRowCallbackHandler
{
voidproce***ow(ResultSetrs)throwsSQLException;
}
org.springframework.jdbc.core.RowMapper.ResultSetExtractor的精简版,功能类似于RowCallbackHandler,也只关注处理单行的结果,不过,处理后的结果会由ResultSetExtractor实现类进行组合。RowMapper的接口定义如下:

publicinterfaceRowMapper
{
ObjectmapRow(ResultSetrs,introwNum)throwsSQLException;
}
为了说明这三种Callback接口的使用和相互之间的区别,我们暂且设定如下场景:
数据库表customer中存在多行信息,对该表查询后,我们需要将每一行的顾客信息都映射到域对象Customer中,并以java.util.List的形式返回所有的查询结果。

现在,我们分别使用这三种Callback接口对customer表进行查询:

  1. //org.springframework.jdbc.core.ResultSetExtractor

  2. ListcustomerList=(List)jdbcTemplate.query("select*fromcustomer",newResultSetExtractor(){

  3. publicObjectextractData(ResultSetrs)throwsSQLException,DataAccessException{

  4. Listcustomers=newArrayList();while(rs.next()){Customercustomer=newCustomer();customer.setFirstName(rs.getString(1));customer.setLastName(rs.getString(2));

  5. //...

  6. customers.add(customer);//listaddetim

  7. }

  8. returncustomers;//returnlist

  9. }

  10. });

  11. //org.springframework.jdbc.core.RowMapper.

  12. ListcustomerList=jdbcTemplate.query("select*fromcustomer",newRowMapper(){

  13. publicObjectmapRow(ResultSetrs,introwNumber)throwsSQLException{//rowNumber什么时候用到?

  14. Customercustomer=newCustomer();

  15. customer.setFirstName(rs.getString(1));

  16. customer.setLastName(rs.getString(2));

  17. //...

  18. returncustomer;//returnsingleobject

  19. }

  20. });

  21. //org.springframework.jdbc.core.RowCallbackHandler

  22. finalListcustomerList=newArrayList();//finalList,匿名内部类只能用不可变的外部局部变量

  23. jdbcTemplate.query("select*fromcustomer",newRowCallbackHandler(){

  24. publicvoidproce***ow(ResultSetrs)throwsSQLException{//returnvoid

  25. Customercustomer=newCustomer();

  26. customer.setFirstName(rs.getString(1));

  27. customer.setLastName(rs.getString(2));

  28. //...

  29. customerList.add(customer);//addtheresultintothelist,

  30. }

  31. });

//org.springframework.jdbc.core.ResultSetExtractor
List customerList = (List)jdbcTemplate.query("select * from customer", new ResultSetExtractor(){ 
	public Object extractData(ResultSet rs) throws SQLException,DataAccessException {
		List customers = new ArrayList(); while(rs.next()) { Customer customer = new Customer();customer.setFirstName(rs.getString(1)); customer.setLastName(rs.getString(2)); 
		//...
		customers.add(customer); //list add etim
		} 
		return customers; //return list
	}
}); 
		
//org.springframework.jdbc.core.RowMapper.
List customerList = jdbcTemplate.query("select * from customer", new RowMapper(){
	public Object mapRow(ResultSet rs, int rowNumber) throws SQLException { //rowNumber 什么时候用到?
	Customer customer = new Customer(); 
	customer.setFirstName(rs.getString(1));
	customer.setLastName(rs.getString(2)); 
	//... 
	return customer; //return single object
	}
}); 


//org.springframework.jdbc.core.RowCallbackHandler
final List customerList = new ArrayList(); //final List,匿名内部类只能用不可变的外部局部变量
jdbcTemplate.query("select * from customer", new RowCallbackHandler(){ 
	public void proce***ow(ResultSet rs) throws SQLException { //return void
	Customer customer = new Customer(); 
	customer.setFirstName(rs.getString(1));
	customer.setLastName(rs.getString(2)); 
	//... 
	customerList.add(customer); //add the result into the list,
	}
});


如果你没有发现最大的差异在哪里,那么容我细表:
使用三种Callback接口作为参数的query方法的返回值不同:

以ResultSetExtractor作为方法参数的query方法返回Object型结果,要使用查询结果,我们需要对其进行强制转型;
//该object是一个list,为什么不直接返回list?之所以不做过多的限制就是为了让别的方法在它的基础上更方便的集成,也能给开发者带来更大的灵活性

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

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

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

使用RowMapper比直接使用ResultSetExtractor要方便的多,只负责处理单行结果就行,现在,我们只需要将单行的结果组装后返回就行,剩下的工作,全部都是JdbcTemplate内部的事情了。实际上,JdbcTemplae内部会使用一个ResultSetExtractor实现类来做其余的工作,毕竟,该做的工作还得有人做不是?!

JdbcTemplae内部使用的这个ResultSetExtractor实现类为org.springframework.jdbc.core.RowMapperResultSetExtractor,它内部持有一个RowMapper实例的引用,当处理结果集的时候,会将单行数据的处理委派给其所持有的RowMapper实例,而其余工作它负责:

  1. publicObjectextractData(ResultSetrs)throwsSQLException{

  2. Listresults=(this.rowsExpected>0?newArrayList(this.rowsExpected):newArrayList());

  3. introwNum=0;

  4. while(rs.next()){

  5. results.add(this.rowMapper.mapRow(rs,rowNum++));//rownum行号

  6. }

  7. returnresults;

  8. }

public Object extractData(ResultSet rs) throws SQLException { 
	List results = (this.rowsExpected > 0 ? new ArrayList(this.rowsExpected) : new ArrayList()); 
	int rowNum = 0; 
	while (rs.next()) { 
		results.add(this.rowMapper.mapRow(rs, rowNum++)); //rownum 行号
	} 
	return results; 
} 


这下应该清楚为啥RowMapper为啥就处理单行结果就能完成ResultSetExtractor颇费周折的工作了吧?!


RowCallbackHandler虽然与RowMapper同是处理单行数据,不过,除了要处理单行结果,它还得负责最终结果的组装和获取工作,在这里我们是使用当前上下文声明的List取得最终查询结果,不过,我们也可以单独声明一个RowCallbackHandler实现类,在其中声明相应的集合类,这样,我们可以通过该RowCallbackHandler实现类取得最终查询结果:

  1. publicclassGenericRowCallbackHandlerimplementsRowCallbackHandler{

  2. privateListcollections=newArrayList();

  3. publicvoidproce***ow(ResultSetrs)throwsSQLException{

  4. Customercustomer=newCustomer();

  5. customer.setFirstName(rs.getString(1));

  6. customer.setLastName(rs.getString(2));

  7. //...

  8. collections.add(customer);

  9. }

  10. publicListgetResults(){

  11. returncollections;

  12. }

  13. }

  14. GenericRowCallbackHandlerhandler=newGenericRowCallbackHandler();

  15. jdbcTemplate.query("select*fromcustomer",handler());

  16. ListcustomerList=handler.getResults();

public class GenericRowCallbackHandler implements RowCallbackHandler { 
	private List collections = new ArrayList(); 
	public void proce***ow(ResultSet rs) throws SQLException { 
		Customer customer = new Customer(); 
		customer.setFirstName(rs.getString(1)); 
		customer.setLastName(rs.getString(2)); 
		//... 
		collections.add(customer); 
	} 

	public List getResults() { 
		return collections; 
	} 
} 
GenericRowCallbackHandler handler = new GenericRowCallbackHandler(); 
jdbcTemplate.query("select * from customer",handler());
List customerList = handler.getResults();



该使用方式是明了了,不过GenericRowCallbackHandler重用性不佳。RowCallbackHandler因为也是处理单行数据,所以,总得有人来做遍历ResultSet的工作,这个人其实也是一个ResultSetExtractor实现类,它是JdbcTemplate一个内部静态类,名为RowCallbackHandlerResultSetExtractor,一看它的定义你就知道奥秘之所在了:

  1. privatestaticclassRowCallbackHandlerResultSetExtractorimplementsResultSetExtractor{

  2. privatefinalRowCallbackHandlerrch;

  3. publicRowCallbackHandlerResultSetExtractor(RowCallbackHandlerrch){

  4. this.rch=rch;

  5. }

  6. publicObjectextractData(ResultSetrs)throwsSQLException{

  7. while(rs.next()){

  8. this.rch.proce***ow(rs);

  9. }

  10. returnnull;

  11. }

  12. }

private static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor { 
	private final RowCallbackHandler rch; 

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

	public Object extractData(ResultSet rs) throws SQLException { 
		while (rs.next()) { 
			this.rch.proce***ow(rs); 
		} 
		return null; 
	} 
} 

总的来说,内部工作归根结底是由ResultSetExtractor做了,RowCallbackHandler和RowMapper只是为了帮助我们简化使用上的操作而已。所以,实际使用中,RowCallbackHandler和RowMapper才是我们最常用的选择。
对于使用JdbcTemplate进行查询,基本就这些内容了,当然,如果你非要使用基于StatementCallback之类更底层的execute方法的话,那就是你个人说了算啦。不过,要想知道JdbcTemplate中有关查询相关模板方法的更多信息,在实际使用中参考JdbcTemplate的javadoc就可以,当然,有IDE就更便捷了。

http://blog.csdn.net/congqian1120/archive/2008/01/16/2046311.aspx