首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 資料庫基礎

JDBC 呼叫 Oracle 預存程序實務指南

     編輯:Oracle 資料庫基礎

前言

JDBC (Java Database Connectivity) 定義了統一的資料庫操作介面,各資料庫廠商提供驅動程式實作。呼叫 Oracle 預存程序時,核心類別為 java.sql.CallableStatement。本文說明基本呼叫流程、OUT 參數處理、REF CURSOR 結果集回傳,並釐清 execute()、executeUpdate()、executeQuery() 三者在預存程序場景下的異同。

基本呼叫流程

  1. 載入驅動:Class.forName("oracle.jdbc.OracleDriver")
  2. 取得連線:DriverManager.getConnection(url, user, pwd)
  3. 準備呼叫:conn.prepareCall("{call procedure_name(?, ?)}")
  4. 綁定參數:setXxx() 設定 IN 參數,registerOutParameter() 註冊 OUT 參數
  5. 執行:execute() / executeUpdate() / executeQuery()
  6. 取得結果:getXxx() 讀取 OUT 參數,getObject() 取得 REF CURSOR
  7. 釋放資源:關閉 CallableStatement、Connection

範例一:單一 OUT 參數(標量回傳)

Oracle 預存程序

CREATE OR REPLACE PROCEDURE sp_get_value (
    p_out OUT NUMBER
) AS
BEGIN
    p_out := 10;
END;
/

Java 程式碼

String sql = "{call sp_get_value(?)}";
try (Connection conn = DriverManager.getConnection(url, user, pwd);
     CallableStatement cs = conn.prepareCall(sql)) {
    
    cs.registerOutParameter(1, Types.INTEGER);
    cs.executeUpdate(); // 或 execute()、executeQuery() 均可
    
    int result = cs.getInt(1); // 取得 10
    System.out.println("回傳值:" + result);
}

範例二:回傳 REF CURSOR(結果集)

Oracle 預存程序

CREATE OR REPLACE PROCEDURE sp_get_dept (
    p_cursor OUT SYS_REFCURSOR
) AS
BEGIN
    OPEN p_cursor FOR SELECT deptno, dname FROM dept;
END;
/

提示: Oracle 12c+ 內建 SYS_REFCURSOR 型別,無需自訂套件。

Java 程式碼

String sql = "{call sp_get_dept(?)}";
try (Connection conn = DriverManager.getConnection(url, user, pwd);
     CallableStatement cs = conn.prepareCall(sql)) {
    
    cs.registerOutParameter(1, OracleTypes.CURSOR);
    cs.execute(); // 三種執行方法皆可
    
    try (ResultSet rs = (ResultSet) cs.getObject(1)) {
        while (rs.next()) {
            System.out.println(rs.getInt("deptno") + " - " + rs.getString("dname"));
        }
    }
}

三種執行方法的異同分析

方法回傳型別適用場景預存程序場景行為
execute()boolean通用,可能產生多結果集最通用,支援 OUT 參數與 REF CURSOR,推薦使用
executeUpdate()int (影響筆數)DML (INSERT/UPDATE/DELETE)可執行預存程序,忽略結果集,僅回傳更新筆數(通常為 0 或 -1)
executeQuery()ResultSetSELECT 查詢可執行預存程序,若有 REF CURSOR 會拋出例外(預期單一 ResultSet),不建議使用

結論: 呼叫預存程序時,統一使用 execute() 最為穩健,可同時處理 OUT 參數與多重 REF CURSOR。

常見錯誤與解決方案

錯誤現象原因解決
ORA-06550: PLS-00306參數數量/型別不匹配檢查 Java 端 registerOutParameter 索引、型別與 PL/SQL 宣告一致
ClassCastException: cannot cast to ResultSet未正確註冊 CURSOR 型別確認 cs.registerOutParameter(idx, OracleTypes.CURSOR)
游標已關閉ResultSet 使用後未正確關閉,或連線已提交/關閉在同一交易/連線存活期間處理完 ResultSet,使用 try-with-resources
驅動類別找不到Classpath 缺少 ojdbc.jarMaven 引入 com.oracle.database.jdbc:ojdbc11 或手動加入 JAR

進階技巧

1. 使用 Named Parameter(Oracle 11g+ JDBC 4.0)

cs.registerOutParameter("p_cursor", OracleTypes.CURSOR);
ResultSet rs = (ResultSet) cs.getObject("p_cursor");

提升可讀性,避免索引錯誤。

2. 批次呼叫預存程序

String sql = "{call batch_insert(?, ?)}";
try (CallableStatement cs = conn.prepareCall(sql)) {
    for (int i = 1; i <= 1000; i++) {
        cs.setInt(1, i);
        cs.setString(2, "Name_" + i);
        cs.addBatch();
    }
    cs.executeBatch(); // 單次網路往返完成 1000 次呼叫
}

3. 取得預存程序編譯錯誤

DatabaseMetaData meta = conn.getMetaData();
try (ResultSet rs = meta.getProcedures(null, "SCOTT", "SP_%")) {
    while (rs.next()) {
        System.out.println(rs.getString("PROCEDURE_NAME"));
    }
}

建議:將預存程序呼叫封裝為 DAO 層方法,統一異常轉換、日誌記錄與資源管理,上層業務邏輯保持簡潔。

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