JDBC 是 Java 應用存取資料庫的標準介面,但其效能瓶頸往往隱藏在分散的程式碼中。本文提出基於「裝飾模式」的 Wrapper 架構,無侵入式地攔截 Connection、Statement、ResultSet 核心介面,精準測量 SQL 執行時間、資料提取耗時,幫助開發者快速定位效能熱點。
JDBC 核心三介面:Connection (取得連線)、Statement (執行 SQL)、ResultSet (讀取結果)。典型流程:
Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM table");
while (rs.next()) { /* 處理資料 */ }
驅動程式廠商提供具體實作 (如 OracleConnection),標準 API 僅定義介面。
核心思想:以實作同介面的 Wrapper 類別包裝原始物件,轉發所有方法調用,於關鍵點植入計時邏輯。應用程式僅需在取得連線處替換為 Wrapper,其餘邏輯不變。
Connection,轉發大多數方法createStatement()、prepareStatement()、prepareCall() 回傳對應的 Statement WrappergetMetaData() 回傳 DatabaseMetaDataWrapper 確保一致性if (conn instanceof ConnectionWrapper) conn = ((ConnectionWrapper)conn).realConnection();StatementWrapper 實作 Statement,持有 ConnectionWrapper 參考PreparedStatementWrapper 繼承 StatementWrapper 實作 PreparedStatementCallableStatementWrapper 繼承 PreparedStatementWrapper 實作 CallableStatementgetConnection() 回傳 ConnectionWrapperexecuteQuery()、executeUpdate()、execute()、executeBatch() 植入計時Array 物件輸入輸出封裝/解封裝ResultSet,轉發方法getStatement() 回傳 StatementWrappergetArray() 回傳 SQLArrayWrappernext() 方法,因大量資料提取時耗時可能超過 SQL 執行本身DatabaseMetaDataWrapper:確保回傳的 Connection 為 WrapperSQLArrayWrapper:包裝 java.sql.Array,確保其 getResultSet() 回傳 Wrapper使用 ThreadLocal 或 Hashtable 以執行緒為鍵記錄開始時間:
private static Hashtable queryTime = new Hashtable();
public static void startLogSqlQuery(Thread t, String sql) {
queryTime.put(t, new Long(System.currentTimeMillis()));
}
public static void endLogSqlQuery(Thread t, String sql) {
long time = System.currentTimeMillis() - ((Long)queryTime.get(t)).longValue();
System.out.println("Time: " + time + " millis for SQL query " + sql);
queryTime.remove(t);
}
// 同理實作 startLogSqlNext / endLogSqlNext 監測 ResultSet.next()
輸出範例:Time: 53 millis for SQL query SELECT * FROM JACKTABL
定位瓶頸後,可針對性優化:SQL 調優、索引策略、連線池參數、批次處理、快取機制等。Wrapper 架構為持續效能治理奠定基礎。