簡體   English   中英

使用JDBC將SYS_REFCURSOR作為IN參數調用PL / SQL過程

[英]Calling PL/SQL procedure with SYS_REFCURSOR as IN parameter using JDBC

我試圖理解如何調用PL / SQL過程,該過程將SYS_REFCURSOR作為IN參數。

考慮以下PL / SQL過程:

print_cursor_contents(myCursor SYS_REFCURSOR , row_count OUT NUMBER);

在將值綁定到IN參數時,我使用setXXX方法?

給我一個帶有單獨游標記錄字段的java類,因為它的成員和這個類的實例數組似乎是表示plsql CURSOR的正確方法。 當我這樣做時,我得到一個SQLException:

我使用了以下set方法

         callStmt.setObject(1, curRec);

以下是使用上述語句時的例外情況:

Exception occured in the database
Exception message: Invalid column type
java.sql.SQLException: Invalid column type
    at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8921)
    at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8396)
    at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:9176)
    at oracle.jdbc.driver.OracleCallableStatement.setObject(OracleCallableStatement.java:5024)
    at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:234)
    at com.rolta.HrManager.printMaxSalAllDept(HrManager.java:1022)
    at com.rolta.HrManager.main(HrManager.java:1116)
Database error code: 17004

給我一個帶有單獨游標記錄字段的java類,因為它的成員和這個類的實例數組似乎是表示plsql CURSOR的正確方法。

我不同意。

如果您有一個存儲的函數或過程,它返回一個引用游標或將一個引用游標作為一個OUT參數,那么引用游標將作為ResultSet從JDBC中取出。 因此,如果可以使用SYS_REFCURSOR參數調用存儲過程,我會懷疑ResultSet是您需要傳遞的。

事實上,我的懷疑得到了證實。 如果你看一下Oracle對CallableStatement的擴展, OracleCallableStatement ,它從它的超OraclePreparedStatement繼承了一個setCursor(int, ResultSet)方法。 因此,您可以將CallableStatementOracleCallableStatement ,調用setCursor方法,然后離開。

除了這種方法實際上不起作用。

如果您嘗試調用setCursorOracleCallableStatement ,你會得到一個異常java.sql.SQLException: Unsupported feature

您可以嘗試使用ResultSet調用setObject ,但只會獲得另一個java.sql.SQLException: Invalid column type異常。

這是一個可以運行以驗證任何一種情況的測試類。 它調用一個存儲過程來獲取引用游標(因此得到一個ResultSet ),然后嘗試將它傳遞給另一個:

import java.sql.*;
import oracle.jdbc.OracleTypes;
import oracle.jdbc.OracleCallableStatement;

public class JavaRefCursorTest {
    public static void main(String[] args) throws Exception {
        Connection conn = DriverManager.getConnection(
                "jdbc:oracle:thin:@localhost:1521:XE", "user", "password");

        try (CallableStatement cstmt1 = conn.prepareCall(
                "{ call java_ref_curs_test.get_ref_cursor(?)}")) {
            cstmt1.registerOutParameter(1, OracleTypes.CURSOR);
            cstmt1.execute();

            try (ResultSet rSet = (ResultSet)cstmt1.getObject(1)) {
                try (CallableStatement cstmt2 = conn.prepareCall(
                        "{ call java_ref_curs_test.print_refcursor(?)}")) {

                    // Uncomment the next line to call setCursor:
                    // ((OracleCallableStatement)cstmt2).setCursor(1, rSet); 

                    // Uncomment the next line to call setObject:
                    // cstmt2.setObject(1, rSet);

                    cstmt2.execute();
                }
            }
        }
    }
}

java_ref_curs_test的兩個過程采用單個SYS_REFCURSOR參數: get_ref_cursor返回一個ref游標, print_refcursor將一個作為參數但不對其執行任何操作。)

那么,你應該使用哪種setXXX方法? 我不會說他們。 您要求的是不可能直接的。

仍然可以調用此過程,但是您必須在PL / SQL中創建引用游標,而不是在Java中,然后將其傳遞給您的過程。

例如,我可以使用以下PL / SQL塊來調用上面示例中使用的兩個過程:

DECLARE
   l_curs   SYS_REFCURSOR;
BEGIN
   java_ref_curs_test.get_ref_cursor(l_curs);
   java_ref_curs_test.print_refcursor(l_curs); 
END;

您可以很容易地從JDBC運行它:將它放在一個字符串中並將其傳遞給Statement.executeUpdate()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM