JdbcTemplate查詢資料 三種callback之間的區別

工程師WWW發表於2015-10-31
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

相關文章