【问题标题】:Calling PL/SQL procedure with SYS_REFCURSOR as IN parameter using JDBC使用 JDBC 以 SYS_REFCURSOR 作为 IN 参数调用 PL/SQL 过程
【发布时间】:2015-01-19 00:04:50
【问题描述】:

我试图了解如何调用将SYS_REFCURSOR 作为IN 参数的PL/SQL 过程。

考虑以下 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 jdbc parameters plsql cursor


【解决方案1】:

对我来说,一个带有单独游标记录字段的 java 类,因为它的成员和这个类的实例数组似乎是表示 plsql CURSOR 的正确方法。

我不同意。

如果您有一个存储函数或过程,它返回一个引用游标或将引用游标作为OUT 参数,则引用游标作为ResultSet 从 JDBC 中出来。因此,如果可以使用SYS_REFCURSOR 参数调用存储过程,我怀疑ResultSet 将是您需要传递的。

事实上,我的怀疑得到了证实。如果你看一下 Oracle 对CallableStatementOracleCallableStatement 的扩展,它从它的超接口OraclePreparedStatement 继承了一个setCursor(int, ResultSet) 方法。因此,您可以将CallableStatement 转换为OracleCallableStatement,调用setCursor 方法,然后就可以走了。

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

如果您尝试在 OracleCallableStatement 上调用 setCursor,您将收到异常 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 返回一个引用游标,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()

【讨论】:

  • 我尝试通过执行选择查询然后使用 setCursor 将其传递给过程来创建“ResultSet”。我也得到了 Unsupported feature sql 异常。即使我使用的是最新的 oracle Jdbc jar
猜你喜欢
  • 2015-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-04
相关资源
最近更新 更多