首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

Apache Commons DbUtils 使用指南:QueryRunner、ResultSetHandler 七大實現類、DbUtils 工具類完整解析

     編輯:MySQL 綜合教學

Apache Commons DbUtils 使用指南:QueryRunner 核心 API、ResultSetHandler 七大實現、DbUtils 工具類完整解析

Commons DbUtils 是對 JDBC 的輕量封裝,不改變 SQL 編寫習慣,卻能消除 90% 的樣板代碼(連接、語句、結果集、關閉、異常處理)。本文系統講解 QueryRunner 構造與執行方法、ResultSetHandler 七大內置實現、DbUtils 關閉工具類,並附帶完整 JUnit 測試代碼。

一、核心類關係

  • QueryRunner:線程安全的執行入口,持有 DataSource 或接受 Connection。
  • ResultSetHandler<T>:函數式接口,將 ResultSet 轉換為業務對象 T。
  • DbUtils:靜態工具類,負責安全關閉 Connection/Statement/ResultSet、載入驅動、提交關閉。

二、QueryRunner 構造方法

// 1. 無參構造:每次執行需傳入 Connection
QueryRunner runner = new QueryRunner();

// 2. DataSource 構造:自動獲取/歸還連接,適合無連接池管理場景
QueryRunner runner = new QueryRunner(dataSource);

三、核心執行方法

方法簽名用途連接管理
query(Connection, sql, params[], rsh)查詢,手動管理連接調用者負責關閉 Connection
query(sql, params[], rsh)查詢,自動從 DataSource 獲取連接內部自動關閉 Connection
query(Connection, sql, rsh)無參查詢調用者負責關閉
update(Connection, sql, params[])增刪改,返回影響行數調用者負責關閉
update(Connection, sql)無參增刪改調用者負責關閉
update(sql, params[])自動連接增刪改內部自動關閉
batch(sql, Object[][] params)批量執行視構造方式而定

四、ResultSetHandler 七大內置實現

處理器返回類型適用場景示例
BeanHandler<T>T單行 → JavaBeannew BeanHandler<>(User.class)
BeanListHandler<T>List<T>多行 → List<JavaBean>new BeanListHandler<>(User.class)
ArrayHandlerObject[]單行 → 對象數組new ArrayHandler()
ArrayListHandlerList<Object[]>多行 → List<數組>new ArrayListHandler()
MapHandlerMap<String,Object>單行 → 鍵值對new MapHandler()
MapListHandlerList<Map<String,Object>>多行 → List<Map>new MapListHandler()
ScalarHandler<T>T單值聚合new ScalarHandler<Long>()

五、DbUtils 關閉工具類

// 安全關閉(null 安全、吞噬 SQLException)
DbUtils.close(connection);
DbUtils.close(statement);
DbUtils.close(resultSet);
DbUtils.closeQuietly(connection, statement, resultSet);  // 批量靜默關閉

// 提交並關閉
DbUtils.commitAndCloseQuietly(connection);

// 載入驅動(無需捕獲 ClassNotFoundException)
boolean ok = DbUtils.loadDriver("com.mysql.jdbc.Driver");

六、連接管理關鍵規則

  • 帶 Connection 參數的 update/query:調用者必須手動關閉 Connection,DbUtils 僅關閉 Statement/ResultSet。
  • 不帶 Connection 參數(DataSource 構造):框架自動獲取並關閉 Connection。
  • 設計初衷:支持事務邊界在外層控制(Service 層開啟事務、傳入 Connection、調用多個 DAO、提交/回滾)。

七、完整 JUnit 測試代碼

public class DbUtilsDemo {
    private QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());

    @Test public void testBeanHandler() throws SQLException {
        User user = runner.query("SELECT * FROM user_info", new BeanHandler<>(User.class));
        System.out.println("beanHandler: " + user);
    }

    @Test public void testBeanListHandler() throws SQLException {
        List users = runner.query("SELECT * FROM user_info", new BeanListHandler<>(User.class));
        users.forEach(System.out::println);
    }

    @Test public void testArrayHandler() throws SQLException {
        Object[] arr = runner.query("SELECT * FROM user_info", new ArrayHandler());
        System.out.println("ID: " + arr[0] + ", Name: " + arr[1]);
    }

    @Test public void testArrayListHandler() throws SQLException {
        List list = runner.query("SELECT * FROM user_info", new ArrayListHandler());
        list.forEach(arr -> System.out.println("ID: " + arr[0] + ", Name: " + arr[1]));
    }

    @Test public void testMapHandler() throws SQLException {
        Map map = runner.query("SELECT * FROM user_info", new MapHandler());
        System.out.println("Username: " + map.get("username"));
    }

    @Test public void testMapListHandler() throws SQLException {
        List> list = runner.query("SELECT * FROM user_info", new MapListHandler());
        list.forEach(m -> System.out.println("User: " + m.get("username") + ", Salary: " + m.get("salary")));
    }

    @Test public void testScalarHandler() throws SQLException {
        Long count = runner.query("SELECT COUNT(*) FROM user_info", new ScalarHandler());
        System.out.println("Total: " + count);
    }
}

八、最佳實踐建議

  1. DAO 層統一使用 QueryRunner + BeanListHandler,返回領域模型。
  2. 事務場景:Service 持有 Connection,傳入 DAO 方法,runner.update(conn, sql, params)。
  3. 複雜映射(嵌套對象、多表連接)改用 ResultSetHandler 自定義實現或遷移 MyBatis。
  4. 連接池首選 HikariCP,配合 DbUtils DataSource 構造器。
  5. 異常統一包裝為 DataAccessException,避免 SQLException 外洩。

DbUtils 以「極簡、不侵入、零依賴」成為輕量級項目、微服務 Sidecar、遷移期過渡層的最佳選擇;複雜業務建議直接上 MyBatis/JPA,獲得完整映射、緩存、動態 SQL 能力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved