如何获取作为数组的存储过程输出参数?

时间:2017-12-08 04:49:43

标签: java oracle stored-procedures jdbc plsql

我一直在开发对存储过程的Java / JDBC调用,但取得了一些成功。但是当输出参数是字符串数组时,我被卡住了。我已成功将标量类型作为输入和输出参数,以及作为输入参数的字符串数组。

这是我的PL / SQL代码:

TYPE StringArray IS TABLE OF VARCHAR2(32767) INDEX BY BINARY_INTEGER;

create or replace package body 
test is
  procedure upper(
    in_array     in StringArray,
    out_array    out StringArray
  ) is
    tmp StringArray := in_array;
  begin
    for i in 0..(tmp.count-1) loop
      tmp(i) := UPPER(tmp(i));
    end loop;
    out_array := tmp;
  end;
end test;

这是我的Java代码:

public void testString(Connection connection) {
    String[] values = { "alpha", "beta", "gamma" };
    try {
       CallableStatement callableStatement = connection.prepareCall("begin test.upper(?, ?); end;");
       DelegatingConnection<OracleConnection> delegatingConnection = (DelegatingConnection<OracleConnection>) new DelegatingConnection(connection);
       OracleConnection oracleConnection = (OracleConnection) delegatingConnection.getInnermostDelegate();
       Array input oracleConnection.createOracleArray("STRINGARRAY", values);
       callableStatement.setObject("in_array", input);
       callableStatement.registerOutParameter("out_array", Types.ARRAY, "STRINGARRAY");
       callableStatement.execute();
       Array output = (Array)callableStatement.getObject("out_array");
       String[] result = (String[])output.getArray();
       System.out.println("Length: " + result.length);  // Prints "Length: 3"
       System.out.println("First: " + result[0]);       // Prints "First: null"
    } (catch SQLException e) {
       // Handle error
    }
}

如果我直接从SQL脚本调用PL / SQL存储过程,它就可以工作。所以我认为存储过程本身没问题。

如果我通过JDBC调用存储过程,它会正常完成。使用调试语句,我已确认values已从Java客户端正确发送到存储过程in_array。也就是说,接收具有适当值的长度为3的阵列。据我所知,out_array被发送回Java客户端。但是,出了点问题。 result的大小为3,但所有元素均为null

如果我检查output,我可以看到它内部有byte[]长度38.这些字节的子序列映射到“ALPHA”,“BETA”和“GAMMA”。因此,看起来数据会将其返回给客户端,但它不会正确转换为String[]

我做错了什么?

1 个答案:

答案 0 :(得分:2)

不要使用关联数组 - 使用集合:

CREATE TYPE StringArray IS TABLE OF VARCHAR2(4000);
CREATE TYPE CLOBArray   IS TABLE OF CLOB;

然后你可以这样做:

public void testString(Connection connection) {
  String[] values = { "alpha", "beta", "gamma" };
  try {
    OracleConnection oc = (OracleConnection) connection;

    ARRAY stringArray = oc.createARRAY( "STRINGARRAY", values ); // Upper case identifier

    OracleCallableStatement st = (OracleCallableStatement) oc.prepareCall(
      "begin test.upper( :in_array, :out_array ); end;"
    );

    st.setARRAYAtName( "in_array", stringArray );
    st.registerOutParameter( "out_array", Types.ARRAY, "STRINGARRAY"); // Upper case again
    st.execute();

    String[] result = (String[])st.getARRAY( 2 ).getArray();

    System.out.println("Length: " + result.length);
    System.out.println("First: " + result[0]);
  } (catch SQLException e) {
    // Handle error
  }
}

如果必须使用PL / SQL关联数组作为过程的输入,则编写一个函数,该函数接受一个集合并输出相应类型的关联数组,然后调用:

BEGIN TEST.UPPER( TO_ASSOC_ARRAY( :in_collection ), :out_array ); END;

注意:这个答案是假设在ojdbc6.jar中使用的Oracle驱动程序似乎没有OracleConnection.createOracleArray() method,但希望它可以随身携带,将oracle.sql.ARRAY更改为{ {1}}并使用较新的方法。