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

Java調用Oracle存儲過程完整實戰:CallableStatement雙模式

     編輯:Oracle 資料庫基礎

JDBC調用架構


Connection → prepareCall("{call proc_name(?,?)}") → CallableStatement
    │
    ├─ setXxx(index, value)     -- 綁定IN/IN OUT參數
    ├─ registerOutParameter(index, Types.XXX) -- 註冊OUT參數類型
    ├─ execute()                -- 執行
    └─ getXxx(index)            -- 獲取OUT/IN OUT參數返回值

模式一:無返回參數(純執行)


import java.sql.*;

public class CallProcNoReturn {
    public static void main(String[] args) throws Exception {
        // 1. 加載驅動 (JDBC 4.0+ 可省略 Class.forName)
        // Class.forName("oracle.jdbc.driver.OracleDriver");

        // 2. 獲取連接
        String url = "jdbc:oracle:thin:@dbhost:1521:ORCL";
        String user = "app_user";
        String pass = "AppPass#123";
        Connection conn = DriverManager.getConnection(url, user, pass);

        // 3. 準備調用:pro1(IN p_id NUMBER)
        CallableStatement cs = conn.prepareCall("{call pro1(?)}");

        // 4. 綁定輸入參數
        cs.setInt(1, 188);

        // 5. 執行
        cs.execute();
        System.out.println("Procedure executed.");

        // 6. 關閉資源
        cs.close();
        conn.close();
    }
}

模式二:帶返回參數(OUT/IN OUT)


import java.sql.*;

public class CallProcWithReturn {
    public static void main(String[] args) throws Exception {
        Connection conn = DriverManager.getConnection(
            "jdbc:oracle:thin:@dbhost:1521:ORCL", "app_user", "AppPass#123");

        // pro2(IN p_id NUMBER, OUT p_result NUMBER)
        CallableStatement cs = conn.prepareCall("{call pro2(?, ?)}");

        // 綁定輸入
        cs.setInt(1, 188);

        // 關鍵:註冊輸出參數類型 (索引從1開始)
        cs.registerOutParameter(2, Types.INTEGER);

        // 執行
        cs.execute();

        // 獲取返回值
        int result = cs.getInt(2);
        System.out.println("Return value: " + result);

        cs.close();
        conn.close();
    }
}

Oracle端存儲過程定義對照


-- 模式一對應
CREATE OR REPLACE PROCEDURE pro1(p_id IN NUMBER) IS
BEGIN
  INSERT INTO log_table(id, created) VALUES (p_id, SYSDATE);
  COMMIT;
END;
/

-- 模式二對應
CREATE OR REPLACE PROCEDURE pro2(p_id IN NUMBER, p_result OUT NUMBER) IS
BEGIN
  SELECT COUNT(*) INTO p_result FROM emp WHERE deptno = p_id;
END;
/

進階場景處理

場景Java處理Oracle定義
IN OUT參數cs.setInt(1, val); cs.registerOutParameter(1, Types.INTEGER); 同一索引綁定+註冊p_val IN OUT NUMBER
游標返回 (REF CURSOR)cs.registerOutParameter(1, OracleTypes.CURSOR); ResultSet rs = (ResultSet) cs.getObject(1);p_rc OUT SYS_REFCURSOR
數組/集合參數ArrayDescriptor desc = ArrayDescriptor.createDescriptor("NUM_TAB", conn); ARRAY arr = new ARRAY(desc, conn, javaArray); cs.setArray(1, arr);TYPE num_tab IS TABLE OF NUMBER; p_arr IN num_tab
異常傳播捕獲SQLException,解析getErrorCode()/getMessage()RAISE_APPLICATION_ERROR(-20001, 'msg')

連接池與資源管理最佳實踐


// 使用 HikariCP / Druid / Tomcat JDBC Pool
// 關鍵配置:
// maximumPoolSize=20
// connectionTimeout=30000
// idleTimeout=600000
// maxLifetime=1800000
// connectionTestQuery=SELECT 1 FROM DUAL

// 業務代碼模板
try (Connection conn = dataSource.getConnection();
     CallableStatement cs = conn.prepareCall("{call pro2(?, ?)}")) {
    cs.setInt(1, 188);
    cs.registerOutParameter(2, Types.INTEGER);
    cs.execute();
    int result = cs.getInt(2);
    return result;
} catch (SQLException e) {
    log.error("Call pro2 failed", e);
    throw new ServiceException("DB_ERROR", e);
}
關鍵提示:
• CallableStatement參數索引從1開始,與JDBC標準一致。
• registerOutParameter必須在execute()前調用,且類型需與Oracle定義精確匹配(Types.INTEGER對應NUMBER、Types.VARCHAR對應VARCHAR2、OracleTypes.CURSOR對應SYS_REFCURSOR)。
• 12c+支援Boolean類型參數,JDBC驅動需ojdbc8.jar+oracle.jdbc.OracleTypes.BOOLEAN。
• 生產環境禁用DriverManager直接獲取連接,強制使用連接池,配合try-with-resources確保資源釋放。
• 高併發場景考慮Statement Caching(conn.setImplicitCachingEnabled(true))減少準備開銷。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved