在 Java 企業級開發中,資料庫連線管理是核心基礎設施之一。本文詳細解析一個功能完整的 DBUtil 工具類,涵蓋連線池建立、SQL 執行與查詢、結果集轉換、連線釋放以及防止連線逾時的定時查詢機制。程式碼基於 Apache Commons DBCP、DbUtils 與 Pool 元件,適合作為專案基礎設施參考。
依賴包下載:java-db-dependency
DBUtil 採用單例模式管理連線池,主要職責包括:
ResultSet 轉為 List<Map<String, Object>>QueryThread 每 2 分鐘執行 select 1 防止連線被資料庫斷開public DBUtil(String dri, String url, String userName, String password, String poolName) {
this.dri = dri;
this.url = url;
this.username = userName;
this.password = password;
this.poolName = poolName;
}
參數說明:
dri:JDBC 驅動全類名(如 com.mysql.jdbc.Driver)url:資料庫連線字串poolName:連線池名稱,同一 Web 容器內不可重複private void StartPool() {
try {
Class.forName(dri);
} catch (ClassNotFoundException e1) { e1.printStackTrace(); }
if (connectionPool != null) ShutdownPool();
connectionPool = new GenericObjectPool(null);
ConnectionFactory cf = new DriverManagerConnectionFactory(url, username, password);
PoolableConnectionFactory pcf = new PoolableConnectionFactory(
cf, connectionPool, null, "SELECT 1", false, true);
Class.forName("org.apache.commons.dbcp.PoolingDriver");
PoolingDriver driver = (PoolingDriver) DriverManager
.getDriver("jdbc:apache:commons:dbcp:");
driver.registerPool(poolName, pcf.getPool());
// 啟動定時查詢執行緒
queryThread = new QueryThread(this);
queryThread.start();
}
關鍵點:
GenericObjectPool 作為連線池實作SELECT 1,false, true 表示不檢查連線是否唯讀、但會測試連線有效性PoolingDriver 註冊連線池,後續透過 jdbc:apache:commons:dbcp:{poolName} 獲取連線// 執行更新類 SQL
public int execute(String sql) throws Exception {
Connection conn = getConnection();
try {
QueryRunner qr = new QueryRunner();
return qr.update(conn, sql);
} finally { Close(conn); }
}
// 查詢(無參數)
public List<Map<String, Object>> query(String sql) throws SQLException {
Connection conn = getConnection();
try {
QueryRunner qr = new QueryRunner();
return qr.query(conn, sql, new MapListHandler());
} finally { Close(conn); }
}
// 查詢(帶參數)
public List<Map<String, Object>> query(String sql, Object param) throws SQLException {
Connection conn = getConnection();
try {
QueryRunner qr = new QueryRunner();
return (List<Map<String, Object>>) qr.query(conn, sql, param, new MapListHandler());
} catch (SQLException e) { e.printStackTrace(); }
finally { Close(conn); }
return null;
}
設計亮點:
QueryRunner 簡化 JDBC 模板代碼MapListHandler 自動將每行結果映射為 Map<String, Object>finally 區塊確保連線歸還池中class QueryThread extends Thread {
private DBUtil dbUtil;
private boolean startQuery = true;
public void run() {
while (true) {
try {
if (startQuery) dbUtil.query("select 1");
} catch (Exception e) { e.printStackTrace(); }
finally {
try { Thread.sleep(120000); } // 2 分鐘
catch (InterruptedException e) { e.printStackTrace(); }
}
}
}
public void setStartQuery(boolean flag) { this.startQuery = flag; }
}
機制說明:
select 1,防止資料庫因閒置超時切斷連線setStartQuery(false) 停止執行緒// 初始化
DBUtil db = new DBUtil(
"com.mysql.jdbc.Driver",
"jdbc:mysql://127.0.0.1:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8",
"root", "password", "mypool"
);
// 查詢
List<Map<String, Object>> list = db.query("SELECT * FROM users WHERE id = ?", 1);
// 更新
int rows = db.execute("UPDATE users SET name = ? WHERE id = ?", new Object[]{"Tom", 1});
catch 僅列印堆疊,生產環境應拋出或記錄日誌getConnection() 加 synchronized,高併發下可能成為瓶頸Close() 先 conn.close() 再 DbUtils.closeQuietly(),順序可調整此 DBUtil 展示了傳統 Java 專案中資料庫存取層的典型封裝方式,涵蓋連線池管理、SQL 執行、結果映射與連線保活等核心功能。雖然依賴的庫版本較舊,但其設計思路對理解連線池原理、DbUtils 使用及防止連線逾時策略仍有參考價值。現代專案建議採用 HikariCP + MyBatis/JdbcTemplate 等成熟框架替代。