Java 程式常以字串拼接方式構建 SQL:
String v_id = "xxxxx";
String v_sql = "SELECT name FROM table_a WHERE id = " + v_id;
// 實際送達資料庫:SELECT name FROM table_a WHERE id = 'xxxxx'
這是 Java 區域變數,**非** Oracle 繫結變數。資料庫收到的是字面常量 SQL,每次值變化即視為新 SQL,觸發硬解析。
| 階段 | 硬解析 | 軟解析 |
|---|---|---|
| 語法檢查 | ✓ | ✓ |
| 語義檢查 (物件存在、權限) | ✓ | ✗ (快取中已驗證) |
| 優化器生成執行計劃 | ✓ (RBO/CBO) | ✗ (重用現有計劃) |
| 存入/查找 Shared Pool | 存入新游標 | 命中現有游標 |
硬解析消耗大量 CPU、Latch 競爭,並導致 Shared Pool 碎片化、命中率下降、SQL 老化加速。
String v_id = "xxxxx";
String v_sql = "SELECT name FROM table_a WHERE id = ?"; // 佔位符
PreparedStatement stmt = conn.prepareStatement(v_sql);
stmt.setString(1, v_id); // 繫結變數賦值
ResultSet rs = stmt.executeQuery();
同一 PreparedStatement 物件重複 setString/executeQuery 即可重用游標,實現軟解析。
setString, setInt, setLong, setDouble, setDate, setTimestampsetBytes (BLOB), setCharacterStream (CLOB) — 注意 Thin 驅動限制,LOB 建議用 Locator API。latch: library cache, latch: shared pool) 顯著降低。Statement 加字串拼接就是繫結變數 → 錯,那是字面值。1=1 基礎條件 + 程式動態拼接 `AND col = ?`,參數索引對應管理。繫結變數是 Oracle Shared Pool 設計的核心預期用法。Java 開發者務必養成 PreparedStatement + setXXX 的肌肉記憶,這是從「能跑」到「跑得快、穩、安全」的分水嶺。