一、结构介绍

高层结构图:

wrappers 包:

handlers 包(部分):

二、功能介绍

Commons DbUtils 是一个对 JDBC 操作进行封装的工具类库,其主要优点如下:

  1. 防止资源泄漏:自动处理资源关闭,避免了繁琐的 JDBC 代码。
  2. 代码整洁:显著减少样板代码。
  3. 自动映射:支持从 ResultSet 自动生成 JavaBeans 属性。
  4. 无依赖:除 JDBC 外无其他依赖包。

三、基本使用

1. 核心类说明

基本用到的类主要有 QueryRunnerResultSetHandler 及其子类。

  • QueryRunner:执行查询的类,可以执行 SELECTINSERTUPDATEDELETE 等语句。QueryRunner 使用 ResultSetHandler 的子类来处理 ResultSet 并返回结果;而包提供的 ResultSetHandler 子类使用 RowProcessor 的子类来处理 ResultSet 中的每一行。RowProcessor 的默认实现为 BasicRowProcessorBeanProcessor 不是 RowProcessor,可以看作一个工具类。
  • ResultSetHandler 及其子类:实现了 Object handle(ResultSet rs) throws SQLException 方法。

    • AbstractListHandler:返回多行 List 的抽象类。
    • ArrayHandler:返回一行的 Object[]
    • ArrayListHandler:返回 List,每行是 Object[]
    • BeanHandler:返回第一个 Bean 对象。
    • BeanListHandler:返回 List,每行是 Bean。
    • ColumnListHandler:返回一列的 List
    • KeyedHandler:返回 Map,具体见代码。
    • MapHandler:返回单个 Map
    • MapListHandler:返回 List,每行是 Map
    • ScalarHandler:返回列的头一个值。

2. 代码示例

建表语句与数据:

DROP TABLE IF EXISTS `test`.`user`;
CREATE TABLE `test`.`user` (
  `name` varchar(10) DEFAULT NULL,
  `password` varchar(10) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

-- 表中数据
-- 'user1', 'pwd1'
-- 'user2', 'pwd2'

User 实体类:

public class User {
    private String name;
    private String pwd;

    public User() {
    }

    public void setName(String val) {
        this.name = val;
    }

    public void setPassword(String val) {
        this.pwd = val;
    }

    public String getName() {
        return name;
    }

    public String getPassword() {
        return pwd;
    }
}

测试类:

package dbutiltest;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.ArrayHandler;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ColumnListHandler;
import org.apache.commons.dbutils.handlers.KeyedHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;

public class TestDbUtils {

    static {
        try {
            Class.forName("org.gjt.mm.mysql.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    public Connection getConnection() {
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/test", "root", "pwd");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    public static void main(String[] args) {
        TestDbUtils u = new TestDbUtils();
        u.testArrayHandler();
        u.testArrayListHandler();
        u.testBeanListHandler();
        u.testMapListHandler();
        u.testColumnListHandler();
        u.testNonQuery();
    }

    public void testArrayHandler() {
        System.out.println("----testArrayHandler----");
        String sql = "select * from user";
        ResultSetHandler handler = new ArrayHandler();
        QueryRunner query = new QueryRunner();
        Connection conn = null;
        try {
            conn = getConnection();
            Object[] arr = (Object[]) query.query(conn, sql, handler);
            for (int i = 0; i < arr.length; i++) {
                System.out.println(arr[i].toString());
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                DbUtils.close(conn);
            } catch (SQLException e) {
                // ignore
            }
        }
    }

    public void testArrayListHandler() {
        System.out.println("----testArrayListHandler----");
        String sql = "select * from user";
        ResultSetHandler handler = new ArrayListHandler();
        QueryRunner query = new QueryRunner();
        Connection conn = null;
        try {
            conn = getConnection();
            List list = (List) query.query(conn, sql, handler);
            for (int i = 0; i < list.size(); i++) {
                Object[] arr = (Object[]) list.get(i);
                for (int j = 0; j < arr.length; j++) {
                    System.out.print(arr[j] + "  ");
                }
                System.out.println();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                DbUtils.close(conn);
            } catch (SQLException e) {
                // ignore
            }
        }
    }

    public void testBeanListHandler() {
        System.out.println("----testBeanListHandler----");
        String sql = "select * from user where name=?";
        Object[] params = new Object[] { "user1" };
        ResultSetHandler handler = new BeanListHandler(User.class);
        QueryRunner query = new QueryRunner();
        Connection conn = null;
        try {
            conn = getConnection();
            List list = (List) query.query(conn, sql, params, handler);
            for (int i = 0; i < list.size(); i++) {
                User user = (User) list.get(i);
                System.out.println(user.getName() + "  " + user.getPassword());
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                DbUtils.close(conn);
            } catch (SQLException e) {
                // ignore
            }
        }
    }

    public void testMapListHandler() {
        System.out.println("----testMapListHandler----");
        String sql = "select * from user where name=?";
        Object[] params = new Object[] { "user1" };
        ResultSetHandler handler = new MapListHandler();
        QueryRunner query = new QueryRunner();
        Connection conn = null;
        try {
            conn = getConnection();
            List list = (List) query.query(conn, sql, params, handler);
            for (int i = 0; i < list.size(); i++) {
                Map user = (Map) list.get(i);
                System.out.println(user.get("name") + "  " + user.get("password"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                DbUtils.close(conn);
            } catch (SQLException e) {
                // ignore
            }
        }
    }

    public void testColumnListHandler() {
        System.out.println("----testColumnListHandler----");
        String sql = "select * from user";
        ResultSetHandler handler = new ColumnListHandler("name");
        QueryRunner query = new QueryRunner();
        Connection conn = null;
        try {
            conn = getConnection();
            List list = (List) query.query(conn, sql, handler);
            for (int i = 0; i < list.size(); i++) {
                System.out.println(list.get(i));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                DbUtils.close(conn);
            } catch (SQLException e) {
                // ignore
            }
        }
    }

    public void testKeyedHandler() {
        System.out.println("----testKeyedHandler----");
        String sql = "select * from user";
        ResultSetHandler handler = new KeyedHandler("name");
        QueryRunner query = new QueryRunner();
        Connection conn = null;
        try {
            conn = getConnection();
            Map map = (Map) query.query(conn, sql, handler);
            Map user = (Map) map.get("user2");
            System.out.println(user.get("password"));
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                DbUtils.close(conn);
            } catch (SQLException e) {
                // ignore
            }
        }
    }

    public void testNonQuery() {
        System.out.println("----testNonQuery----");
        String sql = "insert into `user` values('user_test','pwd_test')";
        QueryRunner query = new QueryRunner();
        Connection conn = null;
        try {
            conn = getConnection();
            query.update(conn, sql);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                DbUtils.close(conn);
            } catch (SQLException e) {
                // ignore
            }
        }
    }
}

3. 关于 wrappers 包

在新建 QueryRunner 时,可以通过覆盖父类的方法 wrap 来使用特定的包装器:

QueryRunner query = new QueryRunner() {
    protected ResultSet wrap(ResultSet rs) {
        return StringTrimmedResultSet.wrap(rs);
    }
};

四、扩展

  1. RowProcessor 接口
  2. ResultSetHandler 接口

说明: 本文基于 commons-dbutils 1.2 版本编写,属于较早期的版本。示例中使用的 MySQL 驱动类名 org.gjt.mm.mysql.Driver 已过时,新版本建议使用 com.mysql.cj.jdbc.Drivercom.mysql.jdbc.Driver,且现代开发中建议结合连接池使用。