| 方法 | 回傳 | 適用場景 |
|---|---|---|
execute(String sql) | boolean (是否有 ResultSet) | DDL、動態 SQL、不確定回傳類型 |
executeUpdate(String sql) | int (影響行數) | INSERT/UPDATE/DELETE |
executeQuery(String sql) | ResultSet | SELECT |
try (Connection conn = ds.getConnection();
Statement stmt = conn.createStatement()) {
// 更新
String sql = "UPDATE employees SET salary = 3000 WHERE id = 103";
boolean hasRs = stmt.execute(sql); // false
int rows = stmt.executeUpdate(sql); // 1
// 查詢
sql = "SELECT id, first_name, last_name, salary FROM employees";
try (ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
System.out.printf("ID:%d, Name:%s %s, Salary:%d%n",
rs.getInt("id"), rs.getString("first_name"),
rs.getString("last_name"), rs.getInt("salary"));
}
}
}
DELIMITER $$
CREATE PROCEDURE `get_emp_name` (
IN p_emp_id INT,
OUT p_emp_name VARCHAR(100)
)
BEGIN
SELECT first_name INTO p_emp_name FROM employees WHERE id = p_emp_id;
END $$
DELIMITER ;
String sql = "{call get_emp_name(?, ?)}"; // JDBC 標準逃逸語法
try (Connection conn = ds.getConnection();
CallableStatement cstmt = conn.prepareCall(sql)) {
// 1. 設定 IN 參數
cstmt.setInt(1, 102);
// 2. 註冊 OUT 參數 (索引從 1 開始)
cstmt.registerOutParameter(2, Types.VARCHAR);
// 3. 執行
cstmt.execute();
// 4. 取得 OUT 參數
String empName = cstmt.getString(2);
System.out.println("Employee 102 name: " + empName); // Zaid
}
// 存儲過程:INOUT p_value INT (乘 2 返回)
String sql = "{call double_value(?)}";
try (CallableStatement cstmt = conn.prepareCall(sql)) {
cstmt.setInt(1, 21); // 設定初始值 (IN)
cstmt.registerOutParameter(1, Types.INTEGER); // 同一索引註冊 OUT
cstmt.execute();
int result = cstmt.getInt(1); // 取得結果 (OUT) -> 42
}
// Oracle: CREATE PROCEDURE get_emps(p_dept_id IN NUMBER, p_cursor OUT SYS_REFCURSOR)
String sql = "{call get_emps(?, ?)}";
try (CallableStatement cstmt = conn.prepareCall(sql)) {
cstmt.setInt(1, 10);
cstmt.registerOutParameter(2, OracleTypes.CURSOR); // 資料庫特定型別
cstmt.execute();
try (ResultSet rs = (ResultSet) cstmt.getObject(2)) {
while (rs.next()) { ... }
}
}
-- IN/OUT/INOUTTypes 標準型別 + 廠商擴充 (如 OracleTypes)SQLException,檢查 getSQLState()、getErrorCode(){call ...} 標準語法支援主流資料庫,避免廠商專屬語法Statement 適合簡單靜態 SQL;PreparedStatement 是參數化查詢主力;CallableStatement 專為存儲過程設計,支援 IN/OUT/INOUT/游標。實務上優先用 PreparedStatement,僅在複雜業務邏輯下沉資料庫、或需原子性批次操作時使用存儲過程。掌握參數註冊、型別映射、資源關閉三要素,即可安全高效調用存儲過程。