JdbcTemplate查詢資料 三種callback之間的區別(ResultSetExtractor,RowMapperRowCallbackHandler)
http://liangfeng366.iteye.com/blog/836077
JdbcTemplate針對資料查詢提供了多個過載的模板方法,你可以根據需要選用不同的模板方法。 如果你的查詢很簡單,僅僅是傳入相應SQL或者相關引數,然後取得一個單一的結果,那麼你可以選擇如下一組便利的模板方法:
int queryForInt(String sql)
int queryForInt(String sql, Object[] args)
long queryForLong(String sql)
long queryForLong(String sql, Object[] args)
Object queryForObject(String sql, Class requiredType)
Object queryForObject(String sql, Object[] args, Class requiredType)
Map queryForMap(String sql)
Map queryForMap(String sql, Object[] args)
比如說,你所查詢的結果就包含一列數字型的結果,或者使用了SQL函式,或者其他單列的結果,我們就可以直接通過這組便利的模板方法進行查詢:
int age = jdbcTemplate.queryForInt("select age from customer where customerId=?",new Object[]{new Integer(100)});
...
long interval = jdbcTemplate.queryForLong("select count(customerId) from customer");
...
String customerName = jdbcTemplate.queryForString("select username from customer where customerId=110");
...
Map singleCustomer = jdbcTemplate.queryForMap("select * from customer limit 1");
...
queryForMap方法與其他方法不同之處在於,它的查詢結果以java.util.Map的形式返回,Map的key對應所查詢表的列名,Map的value當然就是對應key所在列的值啦。 當然了,你也看到了,這組模板方法主要用於單一結果的查詢,使用的時候也請確保你的SQL查詢所返回的結果是單一的,否則,JdbcTemplate將丟擲org.springframework.dao.IncorrectResultSizeDataAccessException異常。
如果查詢的結果將返回多行,而你又不在乎他們是否擁有較強的型別約束,那麼,以下模板方法可以幫助你:
List queryForList(String sql)
List queryForList(String sql, 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:
public interface ResultSetExtractor
{
Object extractData(ResultSet rs) throws SQLException, DataAccessException;
}
在直接處理完ResultSet之後,你可以將處理後的結果以任何你想要的形式包裝後返回。
org.springframework.jdbc.core.RowCallbackHandler. RowCallbackHandler相對於ResultSetExtractor來說,僅僅關注單行結果的處理,處理後的結果可以根據需要存放到當前RowCallbackHandler物件內或者使用JdbcTemplate的程式上下文中,當然,這個完全是看個人愛好了。 RowCallbackHandler的定義如下:
public interface RowCallbackHandler
{
void processRow(ResultSet rs) throws SQLException;
}
org.springframework.jdbc.core.RowMapper. ResultSetExtractor的精簡版,功能類似於RowCallbackHandler,也只關注處理單行的結果,不過,處理後的結果會由ResultSetExtractor實現類進行組合。 RowMapper的介面定義如下:
public interface RowMapper
{
Object mapRow(ResultSet rs, int rowNum) throws SQLException;
}
為了說明這三種Callback介面的使用和相互之間的區別,我們暫且設定如下場景:
資料庫表customer中存在多行資訊,對該表查詢後,我們需要將每一行的顧客資訊都對映到域物件Customer中,並以java.util.List的形式返回所有的查詢結果。
現在,我們分別使用這三種Callback介面對customer表進行查詢:
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);
}
return customers;
}});
List customerList = jdbcTemplate.query("select * from customer", new RowMapper(){
public Object mapRow(ResultSet rs, int rowNumber) throws SQLException {
Customer customer = new Customer();
customer.setFirstName(rs.getString(1));
customer.setLastName(rs.getString(2));
...
return customer;
}});
final List customerList = new ArrayList();
jdbcTemplate.query("select * from customer", new RowCallbackHandler(){
public void processRow(ResultSet rs) throws SQLException {
Customer customer = new Customer();
customer.setFirstName(rs.getString(1));
customer.setLastName(rs.getString(2));
...
customerList.add(customer);
}});
如果你沒有發現最大的差異在哪裡,那麼容我細表:
使用三種Callback介面作為引數的query方法的返回值不同:
以ResultSetExtractor作為方法引數的query方法返回Object型結果,要使用查詢結果,我們需要對其進行強制轉型;
以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例項,而其餘工作它負責:
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++));
}
return results;
}
這下應該清楚為啥RowMapper為啥就處理單行結果就能完成ResultSetExtractor頗費周折的工作了吧?!
RowCallbackHandler雖然與RowMapper同是處理單行資料,不過,除了要處理單行結果,它還得負責最終結果的組裝和獲取工作,在這裡我們是使用當前上下文宣告的List取得最終查詢結果, 不過,我們也可以單獨宣告一個RowCallbackHandler實現類,在其中宣告相應的集合類,這樣,我們可以通過該RowCallbackHandler實現類取得最終查詢結果:
public class GenericRowCallbackHandler implements RowCallbackHandler {
private List collections = new ArrayList();
public void processRow(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,一看它的定義你就知道奧祕之所在了:
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.processRow(rs);
}
return null;
}
}
總的來說,內部工作歸根結底是由ResultSetExtractor做了,RowCallbackHandler和RowMapper只是為了幫助我們簡化使用上的操作而已。 所以,實際使用中,RowCallbackHandler和RowMapper才是我們最常用的選擇。
對於使用JdbcTemplate進行查詢,基本就這些內容了,當然,如果你非要使用基於StatementCallback之類更底層的execute方法的話,那就是你個人說了算啦。 不過,要想知道JdbcTemplate中有關查詢相關模板方法的更多資訊,在實際使用中參考JdbcTemplate的javadoc就可以,當然,有IDE就更便捷了。
本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/congqian1120/archive/2008/01/16/2046311.aspx