在 Java 資料庫開發中,PreparedStatement 是執行參數化 SQL 語句的核心介面。相較於傳統 Statement,它最大的特色在於使用「佔位符」來預編譯 SQL,這不僅能有效防止 SQL 注入攻擊,還能透過預編譯機制提升重複執行的效能。
範例使用的 Student 資料表結構如下:
| 欄位名 | 型別 | 說明 |
|---|---|---|
| ID | INT | 學號(主鍵) |
| name | VARCHAR | 姓名 |
| gender | VARCHAR | 性別 |
public class PreparedStatementDemo {
public static void main(String[] args) {
int id = 1;
String name = "張三";
String gender = "男";
Connection conn = null;
PreparedStatement ps = null;
try {
// 1. 載入 JDBC 驅動程式
Class.forName("com.mysql.jdbc.Driver");
// 2. 建立資料庫連線
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mysql", "root", "111111");
// 3. 定義參數化 SQL(使用 ? 作為佔位符)
String sql = "INSERT INTO student VALUES (?, ?, ?)";
// 4. 建立 PreparedStatement 物件
ps = conn.prepareStatement(sql);
// 5. 依序設定參數值(索引從 1 開始)
ps.setInt(1, id);
ps.setString(2, name);
ps.setString(3, gender);
// 6. 執行更新並取得影響筆數
int result = ps.executeUpdate();
System.out.println("異動筆數:" + result);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 7. 關閉資源(遵循先開後關原則)
closeQuietly(ps);
closeQuietly(conn);
}
}
private static void closeQuietly(AutoCloseable resource) {
if (resource != null) {
try { resource.close(); } catch (Exception ignored) {}
}
}
}
資料庫在第一次執行時會解析、編譯、優化 SQL 並快取執行計畫。後續相同 SQL 只需傳入新參數即可直接執行,大幅降低解析開銷。
參數值會被視為純資料而非 SQL 片段,資料庫引擎不會將其解釋為指令,從根本上杜絕注入風險。
程式執行後,資料表將新增一筆記錄:
| ID | name | gender |
|---|---|---|
| 1 | 張三 | 男 |
控制台輸出:異動筆數:1
addBatch() + executeBatch()INSERT INTO student (id, name, gender) VALUES (?, ?, ?)