使用JDBC将SYS_REFCURSOR作为IN参数调用PL / SQL过程

我试图理解如何调用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 ,它从它的超级OraclePreparedStatementinheritance了一个setCursor(int, ResultSet)方法。 因此,您可以将CallableStatementOracleCallableStatement ,调用setCursor方法,然后离开。

除了这种方法实际上不起作用。

如果您尝试在setCursor上调用setCursor ,您将获得exceptionjava.sql.SQLException: Unsupported feature

您可以尝试使用ResultSet调用setObject ,但只会获得另一个java.sql.SQLException: Invalid column typeexception。

这是一个可以运行的测试类来validation这两种情况。 它调用一个存储过程来获取引用游标(因此得到一个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()