[英]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)
方法。 因此,您可以將CallableStatement
為OracleCallableStatement
,調用setCursor
方法,然后離開。
除了這種方法實際上不起作用。
如果您嘗試調用setCursor
上OracleCallableStatement
,你會得到一個異常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.