首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JDBC Statement 與 CallableStatement 實戰:存儲過程調用完整指南

     編輯:Java 相關知識

Statement 三大執行方法回顧

方法回傳適用場景
execute(String sql)boolean (是否有 ResultSet)DDL、動態 SQL、不確定回傳類型
executeUpdate(String sql)int (影響行數)INSERT/UPDATE/DELETE
executeQuery(String sql)ResultSetSELECT

完整範例:Statement CRUD

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"));
        }
    }
}

CallableStatement:調用資料庫存儲過程

MySQL 存儲過程範例

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 ;

Java 調用代碼

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 參數處理

// 存儲過程: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
}

游標回傳 (ResultSet)

// 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()) { ... }
    }
}

進階技巧與最佳實踐

  1. 參數模式文檔化:在 SQL 註解標註 -- IN/OUT/INOUT
  2. 型別對應:Types 標準型別 + 廠商擴充 (如 OracleTypes)
  3. 例外處理:捕獲 SQLException,檢查 getSQLState()、getErrorCode()
  4. 效能:存儲過程減少網路往返、利用資料庫端編譯計畫,但增加耦合度
  5. 可移植性:{call ...} 標準語法支援主流資料庫,避免廠商專屬語法

總結

Statement 適合簡單靜態 SQL;PreparedStatement 是參數化查詢主力;CallableStatement 專為存儲過程設計,支援 IN/OUT/INOUT/游標。實務上優先用 PreparedStatement,僅在複雜業務邏輯下沉資料庫、或需原子性批次操作時使用存儲過程。掌握參數註冊、型別映射、資源關閉三要素,即可安全高效調用存儲過程。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved