DBUtil 是 Apache 的一个开源项目,它提供了一些类可以让我们方便的使用 JDBC, 它其实就是JDBC的轻量级的封装。使用它最方便的地方在于我们原来使用 JDBC从数据 库中查询得到的结果集需要将每一行数据封装到实体对象中,然后将实体对象加入到集合 中。而使用 DBUtil 可以直接通过 sql 语句得到集合对象或者实体对象,我们不用再一条 一条的取数据,然后填充到对象中,这些工作DBUtil 都替我们完成了。
那么 DBUtil 是怎么知道将结果集的哪个属性的值填充到对象的哪个属性呢?它主要 是通过反射实体类知道的,所以这就要求实体类中的属性必须与结果集中的列的名称是一 致的。后面会详细讲解到
到Apache网站下载DBUtil的jar包,同时也可以下载得到源代码。目前最新版本是1.3 (2009年11月升级到这个版本)
commons-dbutils-1.3.jar这个jar包就是我们要用到的,需要加入到项目构建路径中。
在JDBC中,我们使用Class.forName来加载驱动程序,而DBUtil中提供了org.apache.commons.dbutils.DbUtils类,这个类中定义的方法全部是静态方法,其中有一个loadDriver方法,这个方法就是用来加载驱动程序。 其它的方法还有关闭连接,关闭statement,关闭resultset方法,以及回滚事物 加载MySQL驱动代码:
DbUtils.loadDriver("com.mysql.jdbc.Driver");
DBUtil中的核心类或者接口就是QueryRunner和ResultSetHandler。 QueryRunner是一个类,这个类执行sql语句,包括增,删,改,查的语句,执行sql语句的时候需要提供Connection对象。
对于查询语句,QueryRunner返回查询结果,在1.3版本中,已近开始支持泛型了。那么返回的结果可以是一个实体对象,也可以是一个集合对象。DBUtil需要知道如何处理结果集中的数据,此时就会调用ResultSetHandler的实现类来完成从结果集到对象之间的转换工作,所以QueryRunner在执行查询语句的时候,除了需要传递Connection对象和参数以外,还需要有ResultSetHandler接口的实现类
在DBUtil中,已经有几个已经写好的ResultSetHandler接口的实现类。
BeanHandler类,这个Handler类实现了ResultSetHandler接口,将查询结果的第一行数据转换为一个javaBean对象,对于查询结果中只有一条数据的情况应该使用BeanHandler来处理结果集
BeanListHandler类,这个Handler来也实现了ResultSetHandler接口,它将查询结果的每一行数据转换成javaBean对象,然后将javaBean对象放入到集合中作为结果返回
当然DBUtil中提供的ResultSetHandler接口的实现类不止上面的两个,上面的两个最长用。这些实现类放在org.apache.commons.dbutils.handlers包中,我们可以去查阅相关的API帮助来获得更多的信息.
有些时候需要对结果集进行特殊处理的时候,我们可以自己来编写 ResultSetHandler的实现类。
下面的操作都是正对下面的表,部门表和员工表,进行操作 ,数据库为mysql。
// 添加部门 public static void main(String[] args) throws SQLException { String url = "jdbc:mysql://localhost:3306/myoa?useUnicode=true&characterEncoding=utf8"; String uid = "root"; String pwd = "root"; if (DbUtils.loadDriver("com.mysql.jdbc.Driver")) { Connection conn = DriverManager.getConnection(url, uid, pwd); String sql="INSERT INTO department(deptName, deptFunction)VALUES(?, ?)"; QueryRunner runner=new QueryRunner(); if(runner.update(conn, sql,"渠道部","建立供货渠道")>0){ System.out.println("执行成功!"); } DbUtils.close(conn); }
需要注意的是:QueryRunner执行完SQL语句之后,会自动关闭Statement或者ResultSet,但是连接不会自动关闭,所以我们需要手工关闭连接 QueryRunner的update方法中,第一个是连接对象,第二个是sql语句,后面的是�ぶ械闹担�这个方法支持可变参数。
// 删除部门 public static void main(String[] args) throws SQLException { String url = "jdbc:mysql://localhost:3306/myoa?useUnicode=true&characterEncoding=utf8"; String uid = "root"; String pwd = "root"; if (DbUtils.loadDriver("com.mysql.jdbc.Driver")) { Connection conn = DriverManager.getConnection(url, uid, pwd); String sql="delete from department where deptID=?"; QueryRunner runner=new QueryRunner(); if(runner.update(conn, sql,5)>0){ System.out.println("删除成功!"); } DbUtils.close(conn); }
我们希望查询到的部门信息直接就是一个对象,所以首先定义一个实体类:
public class Department { private int deptID; private String deptName; private String deptFunction; public Department() { super(); } //省略getter/setter …… }
根据主键值查询,因为查询得到的结果只可能有一条记录,所以这里使用BeanListHandler:
//根据编号获取部门对象 public static void main(String[] args) throws SQLException { String url = "jdbc:mysql://localhost:3306/myoa?useUnicode=true&characterEncoding=utf8"; String uid = "root"; String pwd = "root"; if (DbUtils.loadDriver("com.mysql.jdbc.Driver")) { Connection conn = DriverManager.getConnection(url, uid, pwd); String sql="select * from department where deptID=?"; QueryRunner runner=new QueryRunner(); BeanHandler<Department> bh=new BeanHandler<Department>(Department.class); Department dept=runner.query(conn, sql,bh,1); System.out.println(dept.getDeptName()); DbUtils.close(conn); } }
上面BeanHandler后面的泛型指的是结果集被转换之后的类型。
//查询所有的部门 public static void main(String[] args) throws SQLException { String url = "jdbc:mysql://localhost:3306/myoa?useUnicode=true&characterEncoding=utf8"; String uid = "root"; String pwd = "root"; if (DbUtils.loadDriver("com.mysql.jdbc.Driver")) { Connection conn = DriverManager.getConnection(url, uid, pwd); String sql="select * from department"; QueryRunner runner=new QueryRunner(); BeanListHandler<Department> bh=new BeanListHandler<Department>(Department.class); List<Department> dept=runner.query(conn, sql,bh); for (Department department : dept) { System.out.println(department.getDeptName()); } DbUtils.close(conn); } }
首先新建一个员工实体类,由于我们要显示员工的部门名称,所以在实体类中添加了部门名称属性。
public class Employee { private int empID; private String empName; private Date empBirthday; private String empEmail; private String empTelphone; private boolean empSex; private String favourite; private int deptId; private String deptName; public Employee() { } //省略了getter/setter // ... }
执行查询:
编写SQL语句的时候,一定要注意,结果集中的列的名字一定要与实体类中属性的名字一致,否则结果集中列的值将不会填充到实体对象中。
//查询所有员工 public static void main(String[] args) throws SQLException { String url = "jdbc:mysql://localhost:3306/myoa?useUnicode=true&characterEncoding=utf8"; String uid = "root"; String pwd = "root"; if (DbUtils.loadDriver("com.mysql.jdbc.Driver")) { Connection conn = DriverManager.getConnection(url, uid, pwd); String sql="select empID,empName,empBirthday,deptName from employee,department where employee.deptId=department.deptID"; QueryRunner runner=new QueryRunner(); BeanListHandler<Employee> bh=new BeanListHandler<Employee>(Employee.class); List<Employee> emps=runner.query(conn, sql,bh); for (Employee emp: emps) { System.out.println(emp.getEmpID()+" "+emp.getEmpName()+" "+emp.getEmpBirthday()+" "+emp.getDeptName()); } DbUtils.close(conn); } }
DBUtil简化了我们访问数据库 的代码。其中所有的sql语句都是由QueryRunner执行,QueryRunner执行完sql语句之后,会自动关闭ResultSet或者Statement,但是不会关闭Connection对象,需要我们手动关闭连接对象。
在将结果集转换为javaBean对象的时候,要注意结果集中的列要与javaBean的属性一致。