JDBC 開發中,資源關閉(Connection、Statement、ResultSet)代碼繁瑣且易出錯。本文提供兩個生產級工具類:DBTools(簡輕量、基於屬性文件)與 DBToolkit(功能全面、支持多數據庫、內建日誌、批量操作、Sequence 獲取),並重點講解可變參數 closeAll 的優雅設計。
closeAll(Object... objs)利用 Java 5 可變參數特性,實現**順序無關、類型自動識別、異常隔離**的資源釋放:
public static void closeAll(Object... objs) {
if (objs == null) return;
// 嚴格按 ResultSet -> Statement -> Connection 順序關閉
for (Object obj : objs) if (obj instanceof ResultSet) close((ResultSet) obj);
for (Object obj : objs) if (obj instanceof Statement) close((Statement) obj);
for (Object obj : objs) if (obj instanceof Connection) close((Connection) obj);
}
// 單個關閉方法:異常內部吞噬,保證後續資源繼續關閉
private static void close(Connection conn) {
if (conn != null) try { conn.close(); } catch (SQLException e) { log.error("關閉連接異常", e); }
}
private static void close(Statement stmt) { /* 同理 */ }
private static void close(ResultSet rs) { /* 同理 */ }
調用示例:
Connection conn = null;
PreparedStatement pstmt1 = null, pstmt2 = null;
ResultSet rs = null;
try {
conn = DBToolkit.makeConnection(url, props);
pstmt1 = conn.prepareStatement(sql1);
pstmt2 = conn.prepareStatement(sql2);
rs = pstmt1.executeQuery();
// 業務邏輯...
} catch (SQLException e) {
log.error("數據庫操作失敗", e);
} finally {
DBToolkit.closeAll(rs, pstmt1, pstmt2, conn); // 一行搞定,順序隨意
}
jdbc.properties 讀取配置(驅動、URL、用戶、密碼)。makeConnection() 每次創建新連接(無連接池,適合低頻/工具類場景)。close 重載與 closeAll。// 關鍵片段
static {
InputStream in = DBTools.class.getResourceAsStream("/com/.../jdbc.properties");
Properties props = new Properties();
props.load(in);
driverClassName = props.getProperty("jdbc.driver");
url = props.getProperty("jdbc.url");
user = props.getProperty("jdbc.username");
password = props.getProperty("jdbc.password");
}
public static Connection makeConnection() {
Class.forName(driverClassName);
return DriverManager.getConnection(url, user, password);
}
makeConnection(String url, Properties props) 支持任意 JDBC URL 與屬性,適配不同數據源。executeQuery(Connection, String):靜態查詢,返回 ResultSet(調用者需關閉)。executeSQL(Connection, String):靜態更新/DDL,自動關閉 Statement。executeBatchSQL(Connection, List<String>):批量執行,提升大數據寫入性能。sequenceNextval(Connection, seqName) 封裝 SELECT seq.nextval FROM dual,自動處理資源。closeAll:嚴格按 RS -> Stmt -> Conn 順序三輪遍歷,彻底避免順序錯誤。// 批量執行示例
public static void executeBatchSQL(Connection conn, List<String> sqlList) throws SQLException {
Statement stmt = null;
try {
stmt = conn.createStatement();
for (String sql : sqlList) stmt.addBatch(sql);
stmt.executeBatch();
} finally {
close(stmt);
}
}
// Sequence 獲取
public static long sequenceNextval(Connection conn, String seqName) {
Statement stmt = null; ResultSet rs = null;
try {
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT " + seqName + ".nextval FROM dual");
return rs.next() ? rs.getLong(1) : -1L;
} finally {
close(rs); close(stmt);
}
}
| 場景 | 推薦工具類 | 說明 |
|---|---|---|
| 簡單腳本/單元測試/低頻任務 | DBTools | 零依賴,配置外置,輕量 |
| 企業應用/多數據庫/高併發 | DBToolkit + 連接池 | 建議整合 HikariCP/Druid,工具類僅作 SQL 執行/資源關閉封裝 |
| 批量導入/ETL | DBToolkit.executeBatchSQL | 配合連接池預編譯 PreparedStatement 批量更高效 |
makeConnection 改為從 DataSource.getConnection() 獲取。executePreparedQuery(sql, params...) 防注入、提升性能。beginTx()/commitTx()/rollbackTx() 封裝。BeanListHandler 直接映射實體類。良好的 JDBC 工具類核心價值在於:**屏蔽繁瑣資源管理、統一異常處理、提供語義化 API**。本文 closeAll 設計模式(可變參數 + 多輪類型檢查 + 異常隔離)可直接應用於任何需釋放多類資源的場景。DBToolkit 進一步封裝了批量操作、Sequence 獲取等實用功能,是中小型項目快速落地的利器。生產環境務必配合成熟連接池使用。