DBUtilApache 的一个开源项目,它提供了一些类可以让我们方便的使用 JDBC, 它其实就是JDBC的轻量级的封装。使用它最方便的地方在于我们原来使用 JDBC从数据 库中查询得到的结果集需要将每一行数据封装到实体对象中,然后将实体对象加入到集合 中。而使用 DBUtil 可以直接通过 sql 语句得到集合对象或者实体对象,我们不用再一条 一条的取数据,然后填充到对象中,这些工作DBUtil 都替我们完成了。

  那么 DBUtil 是怎么知道将结果集的哪个属性的值填充到对象的哪个属性呢?它主要 是通过反射实体类知道的,所以这就要求实体类中的属性必须与结果集中的列的名称是一 致的。后面会详细讲解到

1. 下载DBUtil

  到Apache网站下载DBUtil的jar包,同时也可以下载得到源代码。目前最新版本是1.3 (2009年11月升级到这个版本)

20110925181357.png

commons-dbutils-1.3.jar这个jar包就是我们要用到的,需要加入到项目构建路径中。

2. 加载数据库驱动程序

  在JDBC中,我们使用Class.forName来加载驱动程序,而DBUtil中提供了org.apache.commons.dbutils.DbUtils类,这个类中定义的方法全部是静态方法,其中有一个loadDriver方法,这个方法就是用来加载驱动程序。 其它的方法还有关闭连接,关闭statement,关闭resultset方法,以及回滚事物 加载MySQL驱动代码:

DbUtils.loadDriver("com.mysql.jdbc.Driver");

3. 核心类和接口QueryRunner和ResultSetHandler

  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的实现类。

4. 使用DBUtil

  下面的操作都是正对下面的表,部门表和员工表,进行操作 ,数据库为mysql。

20110925181612.png

4.1添加部门
// 添加部门
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语句,后面的是?中的值,这个方法支持可变参数。

4.2删除部门
// 删除部门
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);
}
4.3根据部门编号查询部门信息

  我们希望查询到的部门信息直接就是一个对象,所以首先定义一个实体类:

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后面的泛型指的是结果集被转换之后的类型。

4.4查询所有的部门,查询返回一个集合
//查询所有的部门
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);
  }
}
4.5查询每个员工所在的部门

  首先新建一个员工实体类,由于我们要显示员工的部门名称,所以在实体类中添加了部门名称属性。

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

5. 总结

  DBUtil简化了我们访问数据库 的代码。其中所有的sql语句都是由QueryRunner执行,QueryRunner执行完sql语句之后,会自动关闭ResultSet或者Statement,但是不会关闭Connection对象,需要我们手动关闭连接对象。

  在将结果集转换为javaBean对象的时候,要注意结果集中的列要与javaBean的属性一致。