Java - 调用带有数组的PL/SQL存储过程

3

我有一个类似于以下代码的PL/SQL存储过程,我需要在Java中调用:

TYPE AssocArrayVarchar20_t   is table of VARCHAR2(20)   index by BINARY_INTEGER
TYPE AssocArrayVarchar4100_t is table of VARCHAR2(4100) index by BINARY_INTEGER
TYPE AssocArrayNumber_t      is table of NUMBER         index by BINARY_INTEGER

PROCEDURE DATA_WRITE( I_NAME IN AssocArrayVarchar20_t,
                      I_NUM  IN AssocArrayNumber_t,
                      I_NOTE IN AssocArrayVarchar4100_t)
    // Do Stuff
END DATA_WRITE;

我在Java中尝试了以下内容:
CallableStatement stmt = conn.prepareCall("begin DATA_WRITE(?, ?, ?); end;");
stmt.setArray(0, conn.createArrayOf("VARCHAR", new String[]{ name }));
stmt.setArray(1, conn.createArrayOf("NUMBER", new Integer[]{ num }));
stmt.setArray(2, conn.createArrayOf("VARCHAR2", new String[]{ notes }));
stmet.execute;

当我执行这个操作时,createArrayOf()方法会报错:SQLException: Unsupported Feature。我还尝试了setObject()方法和在createArrayOf方法中使用"varchar""AssocArrayVarchar20_t""varchar_t"等参数,但都无法改变结果。
有人知道我哪里做错了吗?我似乎无法让它正常工作。
更新:成功了!
OracleCallableStatement pStmt = (OracleCallableStatement) conn.prepareCall("begin DATA_WRITE(?, ?, ?); end;");
pStmt.setPlsqlIndexTable(1, new String[]{ name }, 1, 1, OracleTypes.VARCHAR, 20);
pStmt.setPlsqlIndexTable(2, new Integer[]{ num }, 1, 1, OracleTypes.NUMBER, 0);
pStmt.setPlsqlIndexTable(3, new String[]{ notes }, 1, 1, OracleTypes.VARCHAR, 4100);
pStmt.execute();

你可能会发现这个问题https://dev59.com/1lzUa4cB1Zd3GeqP4IhP有用。请同时向我们展示数组的定义(例如`AssocArrayVarchar20_t`)。 - user272735
2个回答

3
这是一份官方指南,如果您需要传递数组而不是表格,请参考Oracle指南

Oracle JDBC不支持java.sql.Connection接口的JDBC 4.0方法createArrayOf。该方法只允许匿名数组类型,而所有Oracle数组类型都已命名。请使用Oracle特定的方法oracle.jdbc.OracleConnection.createARRAY。

向Prepared Statement中传递数组

按以下方式将数组传递给prepared statement:

注意:您可以将数组用作IN或OUT绑定变量。将要传递到prepared statement的数组定义为oracle.sql.ARRAY对象。

ARRAY array = oracle.jdbc.OracleConnection.createARRAY(sql_type_name, elements); sql_type_name是一个Java字符串,指定数组的用户定义SQL类型名称,elements是包含元素的Java数组的java.lang.Object。

创建包含要运行的SQL语句的java.sql.PreparedStatement对象。

将准备好的语句转换为OraclePreparedStatement,并使用setARRAY将数组传递给prepared statement。

(OraclePreparedStatement)stmt.setARRAY(parameterIndex, array); parameterIndex是参数索引,array是先前构造的oracle.sql.ARRAY对象。

运行准备好的语句。

注:由 标记结束。

ARRAY array = oracle.jdbc.OracleConnection.createARRAY(sql_type_name, elements); 

他们的意思是:
java.sql.Connection connection = ...
oracle.jdbc.OracleConnection oracleConnection = connection.unwrap(OracleConnection.class);
ARRAY array = oracleConnection.createARRAY(sql_type_name, elements); 

我曾经使用createARRAY()方法将Java数组传递给一个具有PL/SQL表作为输入参数的存储过程。它可以正常工作。此外,请注意Oracle ARRAY类实现了标准的java.sql.Array接口,因此您可以编写Array array = oracle.jdbc.OracleConnection.createARRAY(sql_type_name, elements);,而唯一需要使用的非标准对象是OracleConnection。 - Pino

2
Java 1.6引入了createArrayOf方法,但据我所知,它无法处理Oracle的PL/SQL关联数组。如果您有Oracle JDBC驱动程序,则可以访问oracle.sql类。
您应该能够将CallableStatement向下转换为OracleCallableStatement。从那里,您可以调用setPlsqlIndexTable方法,并且应该能够传递一个Java数组。

将PL/SQL索引-by表参数绑定到IN参数模式。


我得到了“调用'DATA_WRITE'时参数数量或类型错误”的错误,但我有所有3个输入,并且我认为它们是正确的类型。请参见上面的代码。存储过程确实使用VARCHAR2,也许这就是问题所在?但是没有OracleTypes.VARCHAR2 - MiketheCalamity
撤销上一个评论,我拼错了我的存储过程。 - MiketheCalamity

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接