commons-dbutils-1.9.3.jar 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低, 并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。
0、Dbutils的query()的实现原理:
1、万变不离其宗,查询方法只不过是封装了结果集ResultSet转换为map或list的过程。
2、具体实现方法:
(1)以BeanListHandler为例,我们期望“将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里”。代码如下:
Connection connection = JdbcUtils.getConnection(); List<User> userList = new ArrayList<>(); QueryRunner runner = new QueryRunner(); ResultSetHandler<List<User>> rsh = new BeanListHandler<User>(User.class); userList = runner.query(connection,sql,rsh);
在上一篇博文说道,使用Statement或PreparedStatement执行查询,得到结果集ResultSet,然后对结果集遍历,再进行封装处理:
public static <T> List<T> statementExecuteQuery(Class<T> clazz, final String sql){ T entity = null; Statement statement = null; ResultSet resultSet = null; List<T> queryResult = new ArrayList<>(); Connection connection= getConnection(); if (null == connection){ //log.error("Connection is null."); return null; } try { statement = connection.createStatement(); resultSet = statement.executeQuery(sql);//过程一:得到结果集 final List<Map<String, Object>> data = converResultSetToList(resultSet);//过程二:将结果集toList for (Map<String, Object> map : data){//过程三:将结果集中的每一行数据都封装到一个对应的JavaBean实例中 entity = clazz.newInstance(); for (Map.Entry<String, Object> entry : map.entrySet()){ String columnName = entry.getKey(); Object columnValue = entry.getValue(); BeanUtils.setProperty(entity,columnName,columnValue); } queryResult.add(entity); } } catch (Exception e) { e.printStackTrace(); } finally { closeResource(connection,null,null,resultSet); } return queryResult; }
private static List<Map<String, Object>> converResultSetToList(ResultSet resultSet) throws SQLException { if (null == resultSet){ return null; } List<Map<String, Object>> data = new ArrayList<>(); ResultSetMetaData rsmd = resultSet.getMetaData(); while (resultSet.next()){ Map<String, Object> rowData = new HashMap<String, Object>(); for(int i = 0,columnCount = rsmd.getColumnCount();i < columnCount; i++){ rowData.put(rsmd.getColumnName(i + 1),resultSet.getObject(i + 1)); } data.add(rowData); } return data; }
问:Dbutils是怎么做到封装的呢? 先看看查询实现代码:
List<T> entityList = new ArrayList<>(); Connection connection = JdbcUtils.getConnection(); QueryRunner runner = new QueryRunner(); ResultSetHandler<List<User>> rsh = new BeanListHandler<User>(User.class); entityList = (List<T>)runner.query(connection,sql,rsh);
其实很简单,就是把上面三个过程做了封装而已,封装到 runner.query(connection,sql,rsh) 方法中。
仔细一点就是,queryRunner.query(con,sql,rsh)方法有三个参数,第一个是数据库连接对象,第二个是执行数据库查询的sql语句,第三个很重主要了,就是结果集处理ResultSetHandler的实现类。也就是你要将查询出来的一什么形式返回,是返回一个数组,还是JavaBean实例,还是Map结果,还是一个具体的结果ScalarHandler。
ResultSetHandler接口,有一个 handler 方法,queryRunner.query(con,sql,rsh) 方法将查询出来的结果集交给handler 方法来进行处理,按照 rsh 具体实现类的类型来封装处理结果集。
看看源代码:
ResultSetHandler接口:
public interface ResultSetHandler<T> { T handle(ResultSet var1) throws SQLException; }
queryRunner.query(con,sql,rsh)方法:
public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh) throws SQLException { return this.query(conn, false, sql, rsh, (Object[])null); }
private <T> T query(Connection conn, boolean closeConn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException { //略去如参判断code PreparedStatement stmt = null; ResultSet rs = null; Object result = null; try { stmt = this.prepareStatement(conn, sql); this.fillStatement(stmt, params); rs = this.wrap(stmt.executeQuery()); result = rsh.handle(rs);//调用handler方法,处理结果集。 } catch (SQLException var33) { this.rethrow(var33, sql, params); } finally { try { this.close(rs); } finally { this.close(stmt); if (closeConn) { this.close(conn); } } } return result; }BeanListHandler实现类的handler方法如何处理结果集:
public class BeanListHandler<T> implements ResultSetHandler<List<T>> { private final Class<? extends T> type; private final RowProcessor convert; public BeanListHandler(Class<? extends T> type) { this(type, ArrayHandler.ROW_PROCESSOR); } public BeanListHandler(Class<? extends T> type, RowProcessor convert) { this.type = type; this.convert = convert; } //调用RowProcessor对象的toBeanLit方法处理结果集方法 public List<T> handle(ResultSet rs) throws SQLException { return this.convert.toBeanList(rs, this.type); } }
RowProcessor类的toBeanList()方法:
public <T> List<T> toBeanList(ResultSet rs, Class<? extends T> type) throws SQLException { List<T> results = new ArrayList(); if (!rs.next()) { return results; } else { PropertyDescriptor[] props = this.propertyDescriptors(type); ResultSetMetaData rsmd = rs.getMetaData(); int[] columnToProperty = this.mapColumnsToProperties(rsmd, props); do { results.add(this.createBean(rs, type, props, columnToProperty)); } while(rs.next()); return results; } }
不信,我们可以测试一波:
public static void main(String[] args){ String selectSql = "SELECT * FROM userinfos WHERE userName = 'aerfa';"; Object object = dbutilsExecuteQueryUserOne(selectSql); System.out.println(object); } static class MyResultSetHandler implements ResultSetHandler{ @Override public Object handle(ResultSet var1) throws SQLException{ System.out.println("This my ResultSetHandler."); return "myResultSetHandler"; } } public static Object dbutilsExecuteQueryUserOne(final String sql){ Object user = null; Connection connection = JdbcUtils.getConnection(); if(null == connection){ return null; } try { user = new User(); QueryRunner runner = new QueryRunner(); ResultSetHandler rsh = new MyResultSetHandler(); user = runner.query(connection,sql,rsh); } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtils.closeResource(connection,null,null,null); } return user; }
测试结果:
ResultSetHandler的各个实现类:
ArrayHandler:把结果集中的第一行数据转成对象数组。ArrayListHandler:把结果集中的每一行数据都转成一个对象数组,再存放到List中。
BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。
BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List。
ColumnListHandler:将结果集中某一列的数据存放到List中。
KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里(List<Map>),再把这些map再存到一个map里,其key为指定的列。
ScalarHandler:将结果集第一行的某一列放到某个对象。
使用遵从以下步骤:
1.加载JDBC驱动程序类,并用DriverManager来得到一个数据库连接conn。2.实例化 QueryRunner,得到实例化对象runner。
3. runner.update()方法,执行增改删的sql命令,runner.query()方法,得到结果集。
1、使用MapHandler查询单个结果
public static User dbutilsExecuteQueryUserOne(final String sql){ User user = null; Connection connection = JdbcUtils.getConnection(); if(null == connection){ return null; } try { user = new User(); QueryRunner runner = new QueryRunner(); ResultSetHandler<Map<String, Object>> rsh = new MapHandler(); Map<String, Object> data = runner.query(connection,sql,rsh); for(Map.Entry<String, Object> entry : data.entrySet()){ String colunName = entry.getKey(); Object colunValue = entry.getValue(); BeanUtils.setProperty(user,colunName,colunValue); } } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtils.closeResource(connection,null,null,null); } return user; }
2、使用MapListHandler查询多个结果
public static List<User> dbutilsExecuteQueryUsersOne(final String sql){ List<User> userList = new ArrayList<>(); Connection connection = JdbcUtils.getConnection(); if (null == connection){ return null; } try { QueryRunner runner = new QueryRunner(); ResultSetHandler<List<Map<String,Object>>> rsh = new MapListHandler(); List<Map<String,Object>> data = runner.query(connection,sql,rsh); for (Map<String, Object> map : data){ User user = new User(); for (Map.Entry<String, Object> entry : map.entrySet()){ String columnName = entry.getKey(); Object columnValue = entry.getValue(); BeanUtils.setProperty(user,columnName,columnValue); } userList.add(user); } } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtils.closeResource(connection,null,null,null); } return userList; }
3、使用BeanHandler查询单个结果
public static User dbutilsExecuteQueryUserTwo(final String sql){ User user = null; Connection connection = JdbcUtils.getConnection(); if (null == connection){ return null; } try { QueryRunner runner = new QueryRunner(); ResultSetHandler<User> rsh = new BeanHandler<User>(User.class); user = runner.query(connection,sql,rsh); } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.closeResource(connection,null,null,null); } return user; }
4、使用BeanListHandler查询多个结果
public static List<User> dbutilsExecuteQueryUsersTwo(final String sql){ List<User> userList = new ArrayList<>(); Connection connection = JdbcUtils.getConnection(); if (null == connection){ return null; } try { QueryRunner runner = new QueryRunner(); ResultSetHandler<List<User>> rsh = new BeanListHandler<User>(User.class); userList = runner.query(connection,sql,rsh); } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.closeResource(connection,null,null,null); } return userList; }
5、利用反射机制,查询方法通用化
public static <T> T dbutilsExecuteQueryUserOne(Class<T> clazz, final String sql){ T entity = null; Connection connection = JdbcUtils.getConnection(); if(null == connection){ return null; } try { entity = clazz.newInstance(); QueryRunner runner = new QueryRunner(); ResultSetHandler<Map<String, Object>> rsh = new MapHandler(); Map<String, Object> data = runner.query(connection,sql,rsh); for(Map.Entry<String, Object> entry : data.entrySet()){ String colunName = entry.getKey(); Object colunValue = entry.getValue(); BeanUtils.setProperty(entity,colunName,colunValue); } } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtils.closeResource(connection,null,null,null); } return entity; } public static <T> List<T> dbutilsExecuteQueryUsersOne(Class<T> clazz, final String sql){ List<T> entityList = new ArrayList<>(); Connection connection = JdbcUtils.getConnection(); if (null == connection){ return null; } try { QueryRunner runner = new QueryRunner(); ResultSetHandler<List<Map<String,Object>>> rsh = new MapListHandler(); List<Map<String,Object>> data = runner.query(connection,sql,rsh); for (Map<String, Object> map : data){ T entity = clazz.newInstance(); for (Map.Entry<String, Object> entry : map.entrySet()){ String columnName = entry.getKey(); Object columnValue = entry.getValue(); BeanUtils.setProperty(entity,columnName,columnValue); } entityList.add(entity); } } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtils.closeResource(connection,null,null,null); } return entityList; } public static <T> T dbutilsExecuteQueryUserTwo(Class<T> clazz, final String sql){ T entity = null; Connection connection = JdbcUtils.getConnection(); if (null == connection){ return null; } try { QueryRunner runner = new QueryRunner(); ResultSetHandler<User> rsh = new BeanHandler<User>(User.class); entity = (T) runner.query(connection,sql,rsh); } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.closeResource(connection,null,null,null); } return entity; } public static <T> List<T> dbutilsExecuteQueryUsersTwo(Class<T> clazz, final String sql){ List<T> entityList = new ArrayList<>(); Connection connection = JdbcUtils.getConnection(); if (null == connection){ return null; } try { QueryRunner runner = new QueryRunner(); ResultSetHandler<List<User>> rsh = new BeanListHandler<User>(User.class); entityList = (List<T>)runner.query(connection,sql,rsh); } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.closeResource(connection,null,null,null); } return entityList; }
查询:可接受带有填充字符的sql语句,可防止sql注入。
public static <T> T queryByMapHandler(Class<T> clazz, final String sql,Object...args){ T entity = null; Connection connection = JdbcUtils.getConnection(); if(null == connection){ return null; } try { entity = clazz.newInstance(); QueryRunner runner = new QueryRunner(); ResultSetHandler<Map<String, Object>> rsh = new MapHandler(); Map<String, Object> data = runner.query(connection,sql,rsh,args); for(Map.Entry<String, Object> entry : data.entrySet()){ String colunName = entry.getKey(); Object colunValue = entry.getValue(); BeanUtils.setProperty(entity,colunName,colunValue); } } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtils.closeResource(connection,null,null,null); } return entity; } public static <T> List<T> queryByMapListHandler(Class<T> clazz, final String sql, Object...args){ List<T> entityList = new ArrayList<>(); Connection connection = JdbcUtils.getConnection(); if (null == connection){ return null; } try { QueryRunner runner = new QueryRunner(); ResultSetHandler<List<Map<String,Object>>> rsh = new MapListHandler(); List<Map<String,Object>> data = runner.query(connection,sql,rsh,args); for (Map<String, Object> map : data){ T entity = clazz.newInstance(); for (Map.Entry<String, Object> entry : map.entrySet()){ String columnName = entry.getKey(); Object columnValue = entry.getValue(); BeanUtils.setProperty(entity,columnName,columnValue); } entityList.add(entity); } } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtils.closeResource(connection,null,null,null); } return entityList; } public static <T> T queryByBeanHandler(Class<T> clazz, final String sql, Object...args){ T entity = null; Connection connection = JdbcUtils.getConnection(); if (null == connection){ return null; } try { QueryRunner runner = new QueryRunner(); ResultSetHandler<User> rsh = new BeanHandler<User>(User.class); entity = (T) runner.query(connection,sql,rsh,args); } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.closeResource(connection,null,null,null); } return entity; } public static <T> List<T> queryByBeanListHandler(Class<T> clazz, final String sql,Object...args){ List<T> entityList = new ArrayList<>(); Connection connection = JdbcUtils.getConnection(); if (null == connection){ return null; } try { QueryRunner runner = new QueryRunner(); ResultSetHandler<List<User>> rsh = new BeanListHandler<User>(User.class); entityList = (List<T>)runner.query(connection,sql,rsh,args); } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.closeResource(connection,null,null,null); } return entityList; }
6、执行插入、删除、更新操作
/** * 可执行插入、删除、更新操作 * @param sql:一条完整的sql语句 */ public static void executeByUpdate(final String sql){ Connection connection = JdbcUtils.getConnection(); if (null == connection){ return; } try { QueryRunner runner = new QueryRunner(); int num = runner.update(connection, sql); if (0 == num) { //log.error("execute update failed."); } } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.closeResource(connection,null,null,null); } } /** * 可执行插入、删除、更新操作 * @param sql:带有可填充的sql语句 */ public static void executeByUpdate(final String sql, Object... args){ Connection connection = JdbcUtils.getConnection(); if (null == connection){ return; } try { QueryRunner runner = new QueryRunner(); int num = runner.update(connection, sql, args); if (0 == num) { //log.error("execute update failed."); } } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.closeResource(connection,null,null,null); } }
参考: