天天看点

JDBC连接数据库第三步:利用开源框架Dbutils查询数据库原理及实现方案

 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;
    }
           

测试结果:

JDBC连接数据库第三步:利用开源框架Dbutils查询数据库原理及实现方案

 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);
	}
    }
           

参考:

使用DbUtils实现增删改查——ResultSetHandler 接口的实现类

利用ResultSetHandler各实现类来处理查询结果

开源工具DbUtils的使用(数据库的增删改查)

DbUtils

开源框架:DBUtils使用详解