在 Java 資料庫開發中,重複編寫 JDBC 連接、Statement 創建、結果集處理及資源釋放的樣板代碼既繁瑣又容易出錯。本文展示一個基於 ResultSet 與 ResultSetMetaData 的通用查詢方法,能將任意 SELECT 語句的結果自動映射為 List<Map<String, Object>>,並簡要分析其不足與後續優化方向。
/**
* 通用查詢方法:執行 SELECT 語句並返回 List<Map>
* @param sql 完整的 SQL 查詢語句
* @return 查詢結果列表,每個元素為一行數據(列名-值映射)
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public List testResultSet(String sql) {
Connection connection = null;
Statement statement = null;
ResultSet rs = null;
try {
// 1. 獲取數據庫連接
connection = JDBCTools.getConnection();
// 2. 創建 Statement
statement = connection.createStatement();
// 3. 執行查詢,獲取 ResultSet
rs = statement.executeQuery(sql);
// 4. 解析 ResultSetMetaData 獲取列信息
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
// 5. 遍歷結果集,構建 List<Map>
List list = new ArrayList();
while (rs.next()) {
Map rowData = new HashMap();
// 注意:JDBC 列索引從 1 開始,且這裡條件應為 i <= columnCount
for (int i = 1; i <= columnCount; i++) {
rowData.put(metaData.getColumnName(i), rs.getObject(i));
}
list.add(rowData);
}
// 6. 控制台輸出驗證(生產環境建議移除)
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
return list;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
// 7. 統一釋放資源
JDBCTools.release(rs, statement, connection);
}
}
ResultSetMetaData 提供了結果集的元數據:列數、列名、列類型等。通過 getColumnCount() 和 getColumnName(int column),我們能在不知表結構的情況下動態提取每一行數據。
使用 Map<String, Object> 表示單行,鍵為列名,值為 rs.getObject(i) 返回的 Java 對象。這樣無需預先定義實體類,適合臨時查詢、報表導出等場景。
在 finally 塊中調用工具類 JDBCTools.release() 關閉 ResultSet、Statement、Connection,確保不發生連接洩漏。
i < columnCount 會漏掉最後一列,應改為 i <= columnCount。PreparedStatement 並支持參數綁定。public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... params),配合 PreparedStatement。JDBCTools.getConnection()。LIMIT/OFFSET 或 ROWNUM。這個通用查詢方法雖然「很爛」,但展示了 JDBC 元數據編程的核心思想:利用 ResultSetMetaData 實現結果集與集合的自動映射。在理解其原理後,建議直接使用成熟框架(Spring JdbcTemplate、MyBatis、JDBI 等),它們已完美解決上述所有問題。