QueryRunner線程安全,核心方法:
query(sql, ResultSetHandler<T> rsh, params...) → 查詢update(sql, params...) → 增刪改(返回影響行數)ResultSetHandler 實戰| Handler | 返回類型 | 適用場景 | 關鍵行為 |
|---|---|---|---|
ArrayHandler | Object[] | 單行、無實體類映射 | 僅取第一行,列順序對應數組下標 |
ArrayListHandler | List<Object[]> | 多行、無實體類映射 | 每行一個數組,裝入 List |
BeanHandler<T> | T | 單行 → JavaBean | 列名/別名與屬性名需一致(大小寫不敏感) |
BeanListHandler<T> | List<T> | 多行 → JavaBean 列表 | 最常用,自動逐行映射 |
ScalarHandler<T> | T | 聚合查詢、單值 | 三種構造器: • 無參 → 第 1 行第 1 列 • int colIdx → 第 1 行第 N 列(1-based)• String colName → 第 1 行指定列名 |
ColumnListHandler<T> | List<T> | 單列多行 → List | 構造器同 ScalarHandler,提取指定列所有值 |
MapHandler | Map<String,Object> | 單行 → Map | Key=列名,Value=列值 |
MapListHandler | List<Map<String,Object>> | 多行 → Map 列表 | 每行一個 Map |
DataSource ds)QueryRunner qr = new QueryRunner(ds);
// 1. BeanListHandler - 最常用
List<User> users = qr.query("SELECT id, name, email FROM sys_user WHERE status=1",
new BeanListHandler<>(User.class));
// 2. ScalarHandler - 聚合查詢
Long total = qr.query("SELECT COUNT(1) FROM sys_user",
new ScalarHandler<Long>());
// 3. ColumnListHandler - 只拿某一列
List<String> emails = qr.query("SELECT email FROM sys_user",
new ColumnListHandler<String>("email"));
// 4. MapListHandler - 無實體類、動態列
List<Map<String, Object>> rows = qr.query("SELECT * FROM sys_user LIMIT 10",
new MapListHandler());
// 5. 帶參數查詢(? 佔位符,順序綁定)
User u = qr.query("SELECT * FROM sys_user WHERE id=? AND status=?",
new BeanHandler<>(User.class), 1001, 1);
// 例:將多行聚合為 Map<Long, User>,Key 為 id
ResultSetHandler<Map<Long, User>> mapHandler = rs -> {
Map<Long, User> map = new LinkedHashMap<>();
while (rs.next()) {
User user = new User();
user.setId(rs.getLong("id"));
user.setName(rs.getString("name"));
map.put(user.getId(), user);
}
return map;
};
Map<Long, User> userMap = qr.query("SELECT id, name FROM sys_user", mapHandler);
QueryRunner(ds),內部自動獲取/釋放連接。Connection conn = ds.getConnection(),關閉自動提交,傳入 qr.query(conn, sql, handler, params),最後 conn.commit() / rollback() 並 close()。| 坑點 | 後果 | 解決 |
|---|---|---|
列名與屬性名不一致(如 user_name vs userName) | 屬性為 null | SQL 用別名 user_name AS userName,或配置 BasicRowProcessor + GenerousBeanProcessor 支援下劃線轉駝峰 |
ScalarHandler 無參構造器用於多行結果 | 只取第一行,其餘丟棄 | 確認 SQL 僅返回單行(聚合/主鍵查詢) |
忘記關閉 Connection(事務模式) | 連接洩漏、池耗盡 | 用 try-with-resources 或 DbUtils.closeQuietly(conn) |
大結果集直接 BeanListHandler | OOM | 改用 ResultSetIteratorHandler 流式處理,或分頁查詢 |
DbUtils 以 「一個 QueryRunner + N 種 ResultSetHandler」 覆蓋 95% 查詢場景。牢記 BeanListHandler(列表)、ScalarHandler(聚合)、MapListHandler(動態列)三大主力,其餘按需選擇。生產環境務必配合連接池(Druid/HikariCP)並注意事務邊界。