使用 JDBC 从 PL/SQL 存储函数中获取表返回值

Posted

技术标签:

【中文标题】使用 JDBC 从 PL/SQL 存储函数中获取表返回值【英文标题】:Get table return value from PL/SQL stored function using JDBC 【发布时间】:2019-11-20 22:49:52 【问题描述】:

我有一个 PL/SQL 存储函数,它返回一个整数表:

CREATE TYPE INT_TABLE IS TABLE OF INTEGER;

CREATE FUNCTION f (someParam IN INTEGER) RETURN INT_TABLE IS ...

我希望使用 JDBC 来检索此函数的结果,以便我可以以某种方式遍历整数,无论​​是 ResultSetint[] 还是其他。

函数f对数据库进行修改,所以不能在SELECT f(42) FROM DUAL;这样的查询中调用。返回值的存在是为了通知调用者它修改的行的主键。我大概必须使用CallableStatement,但不知道具体如何。从here 汲取灵感,我尝试过:

CallableStatement cs = conn.prepareCall("? = call f(42)");
cs.registerOutParameter(1, Types.ARRAY);
cs.execute();
ResultSet rs = cs.getArray(1).getResultSet();

但是,这导致java.sql.SQLException: Invalid argument(s) in callregisterOutParameter 行上。我无法确定此错误的实际含义,因为文档对可能引发的异常非常笼统。

我花了几个小时在谷歌上搜索,不知道如何继续。是否可以将表类型提取到 Java 中?如果没有,有没有其他方法可以从 PL/SQL 函数中返回多个整数,可以提取到 Java 中?

【问题讨论】:

【参考方案1】:

我在弄清楚后回答我自己的问题。

我非常接近解决方案;我只是错过了在 registerOutParameter 调用中指定类型名称。因此,最终解决方案如下所示:

cs = conn.prepareCall("? = call f(42)");
cs.registerOutParameter(1, Types.ARRAY, "INT_TABLE");
cs.execute();
ResultSet rs = cs.getArray(1).getResultSet();

这是原生 JDBC,不需要任何 Oracle 扩展。

让我感到困惑的另一件事是ResultSet 的结构。它包含两列;第一个是索引,第二个是值 (documentation link)。因此,如果要提取数组的元素,需要为每一行调用rs.getInt(2),而不是rs.getInt(1)

如果想要将结果作为普通数组而不是 ResultSet,则对应的类型是 java.math.BigDecimal,所以它会是

...
cs.execute();
BigDecimal[] array = (BigDecimal[])(cs.getArray(1).getArray());

【讨论】:

以上是关于使用 JDBC 从 PL/SQL 存储函数中获取表返回值的主要内容,如果未能解决你的问题,请参考以下文章

使用 JDBC 从存储过程中获取 Oracle 表类型

带有参数的 PL/SQL 过程/函数从选择查询返回表

是否可以从 jdbc 调用 pl/sql 函数并按名称注册返回值?

对 Oracle 存储函数的 JDBC 调用 - “结构表”类型的 IN 参数

JDBC调用存储过程的例子

PL/SQL自定义函数