Statement 介面家族封裝 SQL 執行邏輯:
Connection con = DriverManager.getConnection(url, "sunny", "");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table2");
| 方法 | 適用 SQL | 回傳值 |
|---|---|---|
executeQuery | SELECT 等產生單一結果集 | ResultSet |
executeUpdate | INSERT/UPDATE/DELETE、DDL (CREATE/DROP TABLE) | 更新列數 (int),DDL 回傳 0 |
execute | 多結果集/更新計數、動態 SQL、預存程序 | boolean (true=有結果集) |
重要:所有執行方法會關閉該 Statement 當前開啟的 ResultSet,重新執行前必須處理完畢。
PreparedStatement/CallableStatement 版本**不接受 SQL 字串參數** (已預編譯),傳入查詢參數會拋出 SQLException。
executeQuery:讀完所有列視為完成。executeUpdate:執行即完成。execute:讀完所有結果集/更新計數始完成。stmt.close() 顯式釋放 DBMS 資源,雖 GC 會自動回收。語法:{keyword ... parameters ...}。驅動掃描轉義子句並轉換為 DBMS 原生語法。
{escape '字元'}% (匹配任意長度)、_ (匹配單字元) 為 LIKE 通配符。需字面匹配時前置轉義字元:
stmt.executeQuery("SELECT name FROM Identifiers WHERE Id LIKE '\\_%' {escape '\\'}");
{fn 函數名(參數)}數值、字串、時間、日期、系統、轉換函數。驅動映射至 DBMS 原生語法或直接實作。範例:
{fn concat('Hot', 'Java')} -- 字串連接
{fn user()} -- 當前資料庫使用者
支援函數列表可透過 DatabaseMetaData.getNumericFunctions()、getStringFunctions() 等查詢。
{d 'yyyy-MM-dd'} → 驅動轉換 (如 Oracle '28-FEB-99'){t 'HH:mm:ss'}{ts 'yyyy-MM-dd HH:mm:ss.f...'} (小數秒可省略){call procedure_name(?, ?)}
{? = call procedure_name(?, ?)} -- 有回傳值
參數可為字面值或 ? 佔位符。DatabaseMetaData.supportsStoredProcedures() 檢查支援性。
{oj outer-join}outer-join := table LEFT OUTER JOIN {table | outer-join} ON search-condition。進階功能,支援度可查 supportsOuterJoins、supportsFullOuterJoins、supportsLimitedOuterJoins。
stmt.setEscapeProcessing(boolean) 預設開啟。效能極度敏感時可關閉。**不適用於 PreparedStatement** (可能預先發送至資料庫)。
僅用於預存程序或動態 SQL 可能回傳多結果集/更新計數組合的罕見情況。
execute(sql),回傳 true (首結果為 ResultSet) 或 false (首結果為更新計數/DDL)。true:getResultSet() 取得首結果集 → 處理 → getMoreResults() 移至下一結果。false:getUpdateCount() 取得首更新計數 → getMoreResults() 移至下一結果。getMoreResults() 回傳 true (下一為 ResultSet) 或 false (下一為更新計數/無結果)。(getResultSet()==null && getUpdateCount()==-1) 或 (getMoreResults()==false && getUpdateCount()==-1)。stmt.execute(queryStringWithUnknownResults);
while (true) {
int rowCount = stmt.getUpdateCount();
if (rowCount > 0) { // 更新計數
System.out.println("Rows changed = " + rowCount);
stmt.getMoreResults();
continue;
}
if (rowCount == 0) { // DDL 或 0 更新
System.out.println("No rows changed or DDL command");
stmt.getMoreResults();
continue;
}
// rowCount == -1:可能為 ResultSet 或無結果
ResultSet rs = stmt.getResultSet();
if (rs != null) {
// 使用 ResultSetMetaData 解析欄位
while (rs.next()) { /* 處理列 */ }
} else {
break; // 無更多結果
}
}
掌握三大 Statement 分工、SQL 轉義語法實現跨資料庫可移植性、多結果集處理邏輯,能應對從簡單查詢到複雜預存程序的各類資料庫操作場景。善用 PreparedStatement 提升重複執行效能,謹慎使用 execute() 處理未知結果結構。