自定义DbUtils工具类

1、Dbutils介绍

Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。

1.1、构造方法

  • 无参构造
    使用无参构造创建QueryRunner对象,执行方法时需要传入Connection对象,且该Connection对象需要手动释放
new QueryRunner().update(
    conn,
    ...
);
  • 有参构造
    使用有参构造创建QueryRunner对象,执行方法时,不需要传入Connection对象 , QueryRunner对象内部会自动释放Connection
new QueryRunner(dataSource).update(
    ...
);

1.2、常用方法

  • update():执行增删改的dml语句
  • query():执行查询的dql语句

1.3、使用

public class Demo1 {
    public static void main(String[] args) {
//        add() ;

//        delete() ;

//        update() ;

//        queryOne() ;
//        queryOne1() ;

//        queryAll() ;
        queryAll1() ;
    }

	// 查全部,使用BeanListHandler保存结果集
    private static void queryAll1() {
        Connection conn = null ;
        try {
            conn = JDBCUtils.getConnection() ;
            List<User> list = new QueryRunner().query(

                    conn,
                    "select * from t_user",
                    new BeanListHandler<User>(User.class)
            ) ;
            System.out.println(list);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(conn , null);
        }
    }
	
	// 查全部
    private static void queryAll() {
        Connection conn = null ;
        try {
            conn = JDBCUtils.getConnection() ;
            List<User> list = new QueryRunner().query(

                    conn,
                    "select * from t_user",
                    new ResultSetHandler<List<User>>() {

                        @Override
                        public List<User> handle(ResultSet resultSet) throws SQLException {
                            ArrayList<User> users = new ArrayList<>();
                            while (resultSet.next()) {
                                User user = new User(resultSet.getInt("id") , resultSet.getString("name") , resultSet.getInt("age"));
                                users.add(user) ;
                            }

                            return users;
                        }
                    }
            ) ;
            System.out.println(list);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(conn , null);
        }
    }

	// 查单条,使用BeanHandler保存结果集
    private static void queryOne1() {
        Connection conn = null ;
        try {
            conn = JDBCUtils.getConnection() ;
            User user = new QueryRunner().query(
                    conn,
                    "select * from t_user where name = ?",
                    new BeanHandler<User>(User.class),
                    "张三"
            );
            System.out.println(user);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(conn , null);
        }
    }

    private static void queryOne() {
        Connection conn = null ;
        try {
            conn = JDBCUtils.getConnection() ;
            User user = new QueryRunner().query(
                    conn,
                    "select * from t_user where name = ?",
                    new ResultSetHandler<User>() {
                        @Override
                        public User handle(ResultSet resultSet) throws SQLException {
                            User user = new User();
                            if (resultSet.next()) {
                                user.setId(resultSet.getInt(1));
                                user.setName(resultSet.getString(2));
                                user.setAge(resultSet.getInt(3));
                            }
                            return user;
                        }
                    } ,
                    "张三"
            );
            System.out.println(user);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

	// 更新
    private static void update() {
        try {
            new QueryRunner(JDBCUtils3.getDataSource()).update(
                "update t_user set name = ? where name = ?" ,
                "晁盖",
                    "宋江"
            );
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

	// 删除
    private static void delete() {
        Connection conn = null ;

        try {
            conn = JDBCUtils.getConnection() ;

            new QueryRunner().update(
                    conn ,
                    "delete from t_user where name= ?" ,
                    "李白"
            );
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(conn , null);
        }
    }

	// 添加
    private static void add() {
        Connection conn = null ;

        try {
            conn = JDBCUtils.getConnection() ;

            new QueryRunner().update(
                    conn ,    // 连接
                    "insert into t_user values(null , ? , ?) ;" ,  // sql语句
                    "宋江" ,
                    30
            ) ;
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(conn , null);
        }
    }
}
  • 注意事项:使用BeanHandlerBeanListHandler保证查询结果的字段名称必须和Java实体类的属性名称要一样,否则属性赋值失败,为null。可以通过取别名的方式避免这一问题

2、自定义DbUtils工具类

2.1、自定义增删改的方法

  • JDBC的代码
// 修改的方法
private static void update() {
        Connection conn = null ;
        PreparedStatement ps = null ;
        try {
            conn = JDBCUtils.getConnection() ;

            String sql = "update t_user set t_name = ? where t_name = ?;" ;

            ps = conn.prepareStatement(sql);

            ps.setString(1 ,"宋江");
            ps.setString(2 ,"晁盖");

            int insert = ps.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(conn , ps);
        }
    }

    // 删除的方法
    private static void delete() {
        Connection conn = null ;
        PreparedStatement ps = null ;
        try {
            conn = JDBCUtils.getConnection() ;

            String sql = "delete from t_user where t_name = ? ;" ;

            ps = conn.prepareStatement(sql);

            ps.setString(1 ,"杜甫");

            int insert = ps.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(conn , ps);
        }
    }

    // 新增的方法
    private static void add() {
        Connection conn = null ;
        PreparedStatement ps = null ;
        try {
            conn = JDBCUtils.getConnection() ;
            
            String sql = "insert into t_user values(null , ? , ?) ;" ;

            ps = conn.prepareStatement(sql);

            ps.setString(1 ,"杜甫");
            ps.setInt(2 , 40);

            int insert = ps.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(conn , ps);
        }
    }
  • 对于上面的代码来说,大部分都是相同的,只有sql语句参数列表不同,所以我们可以先抽取出公共的部分

private static void add/delete/update() {
    Connection conn = null ;
    PreparedStatement ps = null ;
    try {
        conn = JDBCUtils.getConnection() ;
        /*
        
        sql语句不同
        所传入的参数不同
        
        */
        int update = ps.executeUpdate();
        
       } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(conn , ps);
        }
}
  • 对于sql语句,我们使用传参的方式获取,而对于参数的不同(类型不同、数量不同),可以使用可变参来解决
  • 增删改的方法
	/**
     * 类似于DbUtils的update方法
     * @param sql   sql语句
     * @param param 参数列表
     */
    private static void update(String sql , Object... param) {
        Connection conn = null ;
        PreparedStatement ps = null ;
        try {
            conn = JDBCUtils.getConnection() ;

            ps = conn.prepareStatement(sql);

            // 获取sql语句中参数的个数
            int parameterCount = ps.getParameterMetaData().getParameterCount();

            // 使用for循环设置对应的参数
            for (int i = 0; i < parameterCount; i++) {
                ps.setObject(i + 1 , param[i]);
            }
            
            // 执行sql语句
            int insert = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(conn , ps);
        }
    }

2.2、自定义查询方法

JDBC查询数据的代码

// 查询一条数据
private static void queryOne() {
        Connection conn = null ;
        PreparedStatement ps = null ;
        ResultSet rs = null ;

        try {
            conn = JDBCUtils.getConnection() ;
            String sql = "select id , t_name name , age from t_user where t_name = ?" ;
            ps = conn.prepareStatement(sql) ;

            ps.setString(1 , "张三");

            rs = ps.executeQuery() ;
            User user = null ;
            if (rs.next()) {
                user = new User() ;
                user.setId(rs.getInt("id"));
                user.setName(rs.getString("name"));
                user.setAge(rs.getInt("age"));
            }

            System.out.println(user);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(conn , ps , rs);
        }
    }

// 查询多条数据
private static void queryAll() {
        Connection conn = null ;
        PreparedStatement ps = null ;
        ResultSet rs = null ;

        try {
            conn = JDBCUtils3.getConnection() ;
            String sql = "select id , t_name name , age from t_user ;" ;
            ps = conn.prepareStatement(sql) ;

            rs = ps.executeQuery() ;
            ArrayList<User> list = new ArrayList<>();
            while (rs.next()) {
                User user = new User() ;
                user.setId(rs.getInt("id"));
                user.setName(rs.getString("name"));
                user.setAge(rs.getInt("age"));
                list.add(user) ;
            }

            System.out.println(list);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(conn , ps , rs);
        }
    }
  • 对于查询方法,查询一条和查询多条之间的区别有:

    • sql语句不同
    • 参数列表不同
    • 对结果集的封装不同
  • 三处不同,sql语句参数列表都可以通过传参的形式解决,而对结果集的处理让人无从下手,但是又必须要处理,这个时候就需要用到接口,接口就是为了处理那些必须要处理但是当前情况下又不知道会如何处理的问题的。
  • 定义接口MyResultSetHandler,定义抽象方法handler(ResultSet rs),但是对于将来要处理的结果的类型并不知道,所以还需要使用到泛型
public interface MyResultSetHandler<T> {

    T handler(ResultSet rs) throws Exception;

}
  • 查询的方法
  /**
     * 类似于DbUtils的查询方法
     * @param sql       sql语句
     * @param handler   接口对象,用于处理结果集
     * @param param     参数列表
     * @param        泛型,对应未知类型的结果集对象
     * @return          返回值是t
     * @throws Exception    抛出可能出现的异常
     */
    public static<T> T query(String sql , MyResultSetHandler<T> handler , Object... param) throws Exception{
        Connection conn = null ;
        PreparedStatement ps = null ;
        ResultSet rs = null ;

        try {
            conn = JDBCUtils.getConnection() ;
            ps = conn.prepareStatement(sql) ;
            int parameterCount = ps.getParameterMetaData().getParameterCount();

            for (int i = 0; i < parameterCount; i++) {
                ps.setObject(i + 1 , param[i]);
            }

            // 执行查询方法获取到结果集对象
            rs = ps.executeQuery() ;

            // MyResultSetHandler接口调用handler()方法,交给调用该方法的对象去实现抽象方法处理结果集
            T t = handler.handler(rs);

            return t;
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(conn , ps , rs);
        }
        return null ;
    }
  • 查一条记录
// 查询一条数据
private static void queryOne() throws Exception {
        User u = MyDbUtils.query(
                "select * from t_user where id = ? ;" ,
                // 实现接口中的handler()方法来处理结果集
                new MyResultSetHandler<User>() {
                    @Override
                    public User handler(ResultSet rs) throws Exception {
                        User user = new User();
                        if (rs.next()) {
                            user.setId(rs.getInt("id"));
                            user.setName(rs.getString("t_name"));
                            user.setAge(rs.getInt("age"));
                        }
                        return user;
                    }
                },
                1
        ) ;
        System.out.println(u);
    }
  • 查多条记录
// 查询多条数据
private static void queryAll() throws Exception {
        List<User> list = MyDbUtils.query(
                "select * from t_user",
                // 实现接口中的handler()方法处理结果及
                new MyResultSetHandler<List<User>>() {
                    @Override
                    public List<User> handler(ResultSet rs) throws Exception {
                        ArrayList<User> users = new ArrayList<>();

                        while (rs.next()) {
                            int id = rs.getInt("id") ;
                            String name = rs.getString("t_name") ;
                            int age = rs.getInt("age") ;
                            User user = new User(id, name, age);
                            users.add(user) ;
                        }

                        return users;
                    }
                }
        ) ;
        System.out.println(list);
    }

2.3、封装结果集对象

  • 自定义MyBeanHandlerMyBeanListHandler类来对单条记录的结果集和多条记录的结果集进行封装

PropertyDescriptor类

  • PropertyDescriptor 描述 JavaBean 通过一对存储器方法导出的一个属性。
  • 构造方法

    • PropertyDescriptor(String propertyName, Class beanClass):通过调用 getFoosetFoo 存取方法,为符合标准 Java 约定的属性构造一个PropertyDescriptor
  • 常用方法

    • ClassgetPropertyType():获得属性的 Class 对象。
    • MethodgetReadMethod():获得应该用于读取属性值的方法。
    • MethodgetWriteMethod():获得应该用于写入属性值的方法。
  • 对于MyBeanHandler,实现MyResultSetHandler接口,需要有一个字节码对象类型的属性,定义其构造方法,在创建MyBeanHandler对象时传入结果集对象的字节码对象。通过传入的字节码对象创建一个实例对象t、获取到类的属性的数组。

MyBeanHandler

public class MyBeanHander<T> implements MyResultSetHandler<T> {
    // 字节码对象
    private Class<T> clazz ;

    public MyBeanHander(Class<T> clazz) {
        this.clazz = clazz;
    }
    @Override
    public T handler(ResultSet rs) throws Exception {
        // 根据字节码对象创建类的实例
        T t = clazz.newInstance();

        // 利用反射获取到类中的属性
        Field[] fields = clazz.getDeclaredFields();

        if (rs.next()) {
            for (Field field : fields) {
                // 根据对应的属性名获取属性的set方法
                // 获取属性名
                String fieldName = field.getName();
                // 根据属性名获取属性描述对象
                PropertyDescriptor descriptor = new PropertyDescriptor(fieldName , clazz);
                // 根据描述器对象获取写入属性值的方法(set方法)
                Method writeMethod = descriptor.getWriteMethod();
                // 通过反射调用方法
                writeMethod.invoke(t , rs.getObject(fieldName)) ;
            }
        }
        return t;
    }
}

MyBeanListHandler

public class MyBeanListHandler<T> implements MyResultSetHandler<List<T>>{

    private Class<T> clazz ;

    public MyBeanListHandler(Class<T> clazz) {
        this.clazz = clazz;
    }

    @Override
    public List<T> handler(ResultSet rs) throws Exception {
        List<T> list = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();

        while (rs.next()) {
            // 根据字节码对象创建实例
            T t = clazz.newInstance();
            for (Field field : fields) {
                String fieldName = field.getName();

                PropertyDescriptor descriptor = new PropertyDescriptor(fieldName , clazz);
                Method writeMethod = descriptor.getWriteMethod();

                writeMethod.invoke(t , rs.getObject(fieldName)) ;
            }
            list.add(t) ;
        }

        return list;
    }
}

你可能感兴趣的