首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

資料庫操作封裝最佳實踐:JavaBean 設計模式與避坑指南

     編輯:Java 相關知識

許多開發者在封裝資料庫操作時習慣直接返回 ResultSet,這實際上失去了封裝的意義。本文分析常見誤區,提出基於 List<Map> 的資料轉傳方案,並提供完整可用的 DbWrapper 工具類與使用範例,幫助構建健壯的資料存取層。

一、 為什麼不應直接返回 ResultSet?

  1. 耦合度未降低:呼叫端仍需直接操作 JDBC 核心類,與未封裝無異。
  2. 生命週期綁定失效:ResultSet 依賴其所屬 Connection。若連線在方法內關閉,返回的 ResultSet 即失效,操作將拋出異常。

二、 推薦方案:資料轉傳至 List<Map>

將 ResultSet 中所有資料逐行讀取,轉為 Map<String, Object> (鍵為欄位名),收集至 List 返回。此法切斷與連線的依賴,呼叫端無需關心 JDBC 細節。

適用場景: 中小型資料量查詢。大數據量場景下任何封裝都有效能壓力,建議直接操作資料庫或使用流式處理。

三、 DbWrapper 完整實現代碼

import java.sql.*;
import java.util.*;

public class DbWrapper {
    // 連線池靜態變數,生命週期隨 Web 應用
    private static DataSource ds = null;

    // 1. 透過連線池取得連線 (推薦單一資料庫場景)
    // 前置:Tomcat 管理介面需配置 JNDI 資料源 jdbc/MyDataSource
    public static Connection openConnection() throws Exception {
        if (ds == null) {
            Context initContext = new InitialContext();
            Context envContext = (Context) initContext.lookup("java:/comp/env");
            ds = (DataSource) envContext.lookup("jdbc/MyDataSource");
        }
        return ds.getConnection();
    }

    // 2. 透過 JDBC 驅動直接取得連線 (多資料庫或無連線池環境)
    public static Connection openConnection(String driver, String url, String username, String password) throws Exception {
        Class.forName(driver).newInstance();
        return DriverManager.getConnection(url, username, password);
    }

    public static void closeConnection(Connection conn) throws Exception {
        if (conn != null) conn.close();
    }

    // 執行 INSERT/UPDATE/DELETE,返回影響行數
    public static int executeUpdate(String sql) throws Exception {
        int count = 0;
        Connection conn = null;
        Statement stmt = null;
        try {
            conn = openConnection();
            stmt = conn.createStatement();
            count = stmt.executeUpdate(sql);
        } catch (Exception e) { throw e; }
        finally { closeConnection(conn); }
        return count;
    }

    // 執行 SELECT 查詢,返回 List (每筆記錄為一個 Map)
    public static List executeQuery(String sql) throws Exception {
        List list = new ArrayList();
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            conn = openConnection();
            stmt = conn.createStatement();
            rs = stmt.executeQuery(sql);
            ResultSetMetaData rsmd = rs.getMetaData();
            while (rs.next()) {
                Map map = new HashMap();
                for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                    map.put(rsmd.getColumnName(i), rs.getObject(i));
                }
                list.add(map);
            }
        } catch (Exception e) { e.printStackTrace(); }
        finally {
            if (rs != null) rs.close();
            closeConnection(conn);
        }
        return list;
    }
}

四、 使用範例

1. 異動操作

int count = DbWrapper.executeUpdate("INSERT INTO users (name) VALUES ('test')");

2. 查詢操作

List list = DbWrapper.executeQuery("SELECT id, name FROM users");

取值方式一:按欄位名取值 (區分大小寫)

for (int i = 0; i < list.size(); i++) {
    Map map = (Map) list.get(i);
    System.out.println(map.get("name").toString());
}

取值方式二:遍歷 Map 所有鍵值

for (int i = 0; i < list.size(); i++) {
    Map map = (Map) list.get(i);
    for (Iterator it = map.keySet().iterator(); it.hasNext();) {
        String col = it.next().toString();
        Object val = map.get(col);
        System.out.println(col + " = " + (val == null ? "" : val.toString()));
    }
}

五、 關鍵設計要點總結

  • 資源管理:finally 區塊確保 ResultSet、Connection 正確關閉,防止洩漏。
  • 異常處理:executeUpdate 向上拋出異常讓呼叫端決策;executeQuery 記錄堆疊追蹤但返回空列表,避免中斷流程 (可根據業務調整)。
  • 連線池優先:生產環境強烈建議配置 JNDI DataSource,效能與穩定性遠優於驅動直連。
  • 泛型優化:現代代碼建議使用 List<Map<String, Object>> 增強型別安全。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved