天天看點

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使用詳解