首先,須要瞭解spring jdbc查詢時,有三種回調方式來處理查詢的結果集。能夠參考 使用spring的JdbcTemplate進行查詢的三種回調方式的比較,寫得還不錯。java
1.返回對象(queryForObject)spring
有兩種辦法,即兩個容易混淆的方法:sql
//1 public Object queryForObject(String sql, Map<String, ?> paramMap, RowMapper rowMapper) {...} //2 public Object queryForObject(String sql, Map<String, ?> paramMap, Class requiredType) {...}
第一種方法是須要一個實現了RowMapper接口的對象實例做爲第三個參數,實現RowMapper接口的類以下(其中類User.java有id、username、password、dept四個屬性。):數據庫
public class UserRowMapper implements RowMapper<User>{ @Override public User mapRow(ResultSet rs, int rowNum) throws SQLException { User user = new User(); user.setId(rs.getInt(1)); user.setUsername(rs.getString(2)); user.setPassword(rs.getString(3)); user.setDept(4); return user; } }
UserRowMapper.java類在dao中使用方法以下:api
public User queryForObject(String sql, Map<String, Object> params) { return this.getNamedParameterJdbcTemplate().queryForObject(sql,params,new UserRowMapper()); }
在JUnit測試,代碼以下:app
@Test public void getUser(){ String sql = "select * from user where id = :id"; Map<String,Object> map = new HashMap<>(); map.put("id", 1); User user = dao.queryForObject(sql, map); System.out.println(user.getId()); }
輸出結果爲:1。ide
第二種方法,須要傳一個類的類做爲參數,在dao中使用方法以下:測試
public Object queryForObject(String sql, Map<String, Object> params,Class<T> ObjectClass) { try { return this.getNamedParameterJdbcTemplate().queryForObject(sql,params,new BeanPropertyRowMapper<T>(ObjectClass)); } catch (EmptyResultDataAccessException e) { return null;//當查詢記錄爲0時,會拋出EmptyResultDataAccessException異常,因此能夠捕獲它並作適當的處理,如返回null
}
}
用JUnit測試,代碼以下:ui
@Test public void getUser(){ String sql = "select * from user where id = :id"; Map<String,Object> map = new HashMap<>(); map.put("id", 100); User user = (User) dao.queryForObject(sql, map, User.class); System.out.println(user.getId()); }
2.返回對象列表this
經過實現接口org.springframework.jdbc.core.ResultSetExtractor來定製能實現須要的功能的類。此處以能返回一個List<User>的類做爲示例,是仿造上面BeanPropertyRowMapper.java的源碼實現的,但BeanPropertyRowMapper只處理一行記錄:
public class BeanPropertyRowsMapper<T> implements ResultSetExtractor<List<T>> { private Class<T> clazz; private Map<String,PropertyDescriptor> mappedFields; public BeanPropertyRowsMapper(Class<T> clazz){ initialize(clazz); } public Class<T> getClazz() { return clazz; } public void initialize(Class<T> clazz){ this.clazz = clazz; this.mappedFields = new HashMap<String, PropertyDescriptor>(); PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(clazz); for (PropertyDescriptor pd : pds) { if (pd.getWriteMethod() != null) { this.mappedFields.put(pd.getName().toLowerCase(), pd); //將數據庫中格式爲"xxx_xxx"變成駝峯式"xxxXxx"才須要用到下面的代碼 // String underscoredName = underscoreName(pd.getName()); // if (!pd.getName().toLowerCase().equals(underscoredName)) { // this.mappedFields.put(underscoredName, pd); // } } } } // private String underscoreName(String name) { // if (!StringUtils.hasLength(name)) { // return ""; // } // StringBuilder result = new StringBuilder(); // result.append(name.substring(0, 1).toLowerCase()); // for (int i = 1; i < name.length(); i++) { // String s = name.substring(i, i + 1); // String slc = s.toLowerCase(); // if (!s.equals(slc)) { // result.append("_").append(slc); // } // else { // result.append(s); // } // } // return result.toString(); // } public List<T> extractData(ResultSet rs) throws SQLException, DataAccessException { List<T> list = new ArrayList<T>(); Class<T> clazz = getClazz(); try { while(rs.next()){ T t = BeanUtils.instantiate(clazz); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(t); ResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); for(int i = 1;i<=columnCount;i++){ String column = StringUtils.capitalize(JdbcUtils.lookupColumnName(rsmd, i)); PropertyDescriptor pd = this.mappedFields.get(column.replaceAll(" ", "").toLowerCase()); if(pd != null){Object value = JdbcUtils.getResultSetValue(rs, i, pd.getPropertyType()); bw.setPropertyValue(pd.getName(),value); } } list.add(t); } } catch (IllegalArgumentException e) { e.printStackTrace(); } return list; } }
BeanPropertyRowsMapper類在dao中使用方法以下:
public List<User> getUsers(String sql,Map<String, Object> params){ return this.getNamedParameterJdbcTemplate().query(sql, params, new BeanPropertyRowsMapper<User>(User.class)); }
用JUnit測試,代碼以下:
@Test public void getUsers(){ String sql = "select * from user where id < :id"; Map<String,Object> map = new HashMap<>(); map.put("id", 10); List<User> list = dao.getUsers(sql, map); System.out.println(list.size()); }
BeanPropertyRowsMapper類使用到了泛型,因此能夠通用,只需在實例化的時候傳遞一個javabean的Class給構造方法便可。注意:javabean中的屬性名與查詢的結果集的列名必須一致或由數據庫的列名轉成的「駝峯式」,且必須有set方法,不然不一致的或沒有set方法的屬性不會有查詢結果列與之對應,即該屬性不會有值。
可是有時結果集只有不多的幾列,好比只查詢username(用戶名)或者是用戶名和密碼的Map集合等,只需在extractData(ResultSet rs)方法中修改便可。下面來看實現ResultSetExtractor接口的另外一種用法,示例以下:
private class UsernameList implements ResultSetExtractor<List<String>> { public List<String> extractData(ResultSet rs) throws SQLException, DataAccessException { List<String> list = null; while (rs.next()) { if (list == null) { list = new ArrayList<String>(); } list.add(rs.getString(1)); } return list; } }
在dao的使用方法以下:
public List<String> getUsernames(String sql,Map<String, Object> params){ return this.getNamedParameterJdbcTemplate().query(sql, params,new UsernameList()); }
用JUnit測試,代碼以下:
@Test public void getUsernames(){ String sql = "select username from user where id < 10"; Map<String,Object> map = new HashMap<>(); map.put("id", 10); List<String>list = dao.getUsernames(sql, map); System.out.println(list); }
測試結果是打印了幾個用戶名。
第一種可用來返回javabean集合,第二種可用來處理只返回少數列的狀況。