使用 JDBC 以 SYS_REFCURSOR 作为 IN 参数调用 PL/SQL 过程 [英] Calling PL/SQL procedure with SYS_REFCURSOR as IN parameter using JDBC

查看:35
本文介绍了使用 JDBC 以 SYS_REFCURSOR 作为 IN 参数调用 PL/SQL 过程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解如何调用一个将 SYS_REFCURSOR 作为 IN 参数的 PL/SQL 过程.

I am trying to understand how I can call a PL/SQL procedure which takes a SYS_REFCURSOR as IN parameter.

考虑以下 PL/SQL 过程:

Consider the following PL/SQL procedure:

print_cursor_contents(myCursor SYS_REFCURSOR , row_count OUT NUMBER);

在将值绑定到 IN 参数时,我使用哪种 setXXX 方法?

At the time of binding value to the IN parameter which setXXX method do I use ?

对我来说,一个带有单个游标记录字段的 java 类,因为它的成员和此类的实例数组似乎是表示 plsql CURSOR 的正确方法.执行此操作时出现 SQLException:

To me a java Class with individual cursor record fields , as it members and a Array of instances of this class seems the proper way to represent a plsql CURSOR. I get a SQLException when I do this:

我使用了以下设置方法

         callStmt.setObject(1, curRec);

这是我使用上述语句得到的异常:

Here is the exception I got for using the above statement:

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 的正确方法.

To me a java Class with individual cursor record fields , as it members and a Array of instances of this class seems the proper way to represent a plsql CURSOR.

我不同意.

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

If you have a stored function or procedure that either returns a ref cursor or has a ref cursor as an OUT parameter, the ref cursor comes out of JDBC as a ResultSet. So, if it were possible to call a stored procedure with a SYS_REFCURSOR parameter, I'd suspect that a ResultSet would be what you would need to pass.

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

In fact, my suspicions are confirmed. If you take a look at Oracle's extension to CallableStatement, OracleCallableStatement, it inherits a setCursor(int, ResultSet) method from its superinterface OraclePreparedStatement. Therefore, you could cast the CallableStatement to OracleCallableStatement, call the setCursor method, and away you go.

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

Except this approach doesn't actually work.

如果您尝试在 OracleCallableStatement 上调用 setCursor,您将收到异常 java.sql.SQLException: Unsupported feature.

If you try calling setCursor on an OracleCallableStatement, you will get an exception java.sql.SQLException: Unsupported feature.

您可以尝试使用 ResultSet 调用 setObject,但您只会得到另一个 java.sql.SQLException: Invalid column type 异常.

You can try callingsetObject with a ResultSet, but you will only get another java.sql.SQLException: Invalid column type exception.

这是一个测试类,您可以运行以验证这两种情况.它调用一个存储过程来获取一个引用游标(因此是一个 ResultSet),然后尝试将它传递给另一个:

Here's a test class you can run to verify either case. It calls one stored procedure to get a ref cursor (and hence a ResultSet) and then tries to pass it to the other:

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> 将一个作为参数,但什么都不做.)

(The two procedures in the java_ref_curs_test take a single SYS_REFCURSOR parameter: get_ref_cursor returns a ref cursor and print_refcursor takes one as a parameter but does nothing with it.)

那么,您应该使用哪种 setXXX 方法?我不会说他们中的任何一个.您所要求的无法直接实现.

So, which setXXX method should you use? I would say none of them. What you are asking for is not possible directly.

仍然可以调用此过程,但您必须在 PL/SQL 中创建引用游标,而不是在 Java 中,然后将其传递给您的过程.

It may still be possible to call this procedure, but you will have to create the ref cursor in PL/SQL, not in Java, and then pass it to your procedure.

例如,我可以使用下面的 PL/SQL 块来调用上面例子中使用的两个过程:

For example, I could use the following PL/SQL block to call the two procedures used in the above example:

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().

You can fairly easily run this from JDBC: put it in a string and pass it to Statement.executeUpdate().

这篇关于使用 JDBC 以 SYS_REFCURSOR 作为 IN 参数调用 PL/SQL 过程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆