Oracle JDBC调用PL/SQL过程,输入参数为记录表

Oracle JDBC调用PL/SQL过程,输入参数为记录表,jdbc,plsql,ojdbc,Jdbc,Plsql,Ojdbc,我试图从JDBC调用以下pl/sql过程 create or replace PACKAGE test AS type testrec_r is record ( val1 number, val2 varchar2(100) ); type testarr_t is table of testrec_r index by binary_integer; function test_func(i_data in testarr_t, o_sum out number, o_tota

我试图从JDBC调用以下pl/sql过程

create or replace PACKAGE test AS

type testrec_r is record (
 val1 number,
 val2 varchar2(100)
 );

 type testarr_t is table of testrec_r index by binary_integer;

function test_func(i_data in testarr_t, o_sum out number, o_totallength out     number) return number;

END test;
这就是我试图调用它的方式,但没有成功:

StructDescriptor recDescriptor = StructDescriptor.createDescriptor("test.testrec_r", conn);
    STRUCT[] RECORDS_ARRAY = new STRUCT[2];

    for (int i = 0; i < 2; i++) {
         STRUCT oracle_record = new STRUCT(recDescriptor, conn, new
         Object[] {i, "test"});
         RECORDS_ARRAY[i] = oracle_record;
    }

    CallableStatement stmt = conn.prepareCall("{ call TEST.TEST_FUNC(?, ?, ?) }");

    ArrayDescriptor arrayDescriptor = ArrayDescriptor.createDescriptor("TEST.TESTARR_T", conn);
    ARRAY oracle_array = new ARRAY(arrayDescriptor, conn, RECORDS_ARRAY);

    // Bind the input record
    stmt.setArray(1, oracle_array);
    stmt.registerOutParameter(2, Types.NUMERIC);
    stmt.registerOutParameter(3, Types.NUMERIC);
    stmt.executeUpdate();
    double out1 = stmt.getDouble(2);
    double out2 = stmt.getDouble(3);
    return new Object[] { out1, out2 };
StructDescriptor recDescriptor=StructDescriptor.createDescriptor(“test.testrec\u r”,康涅狄格州);
STRUCT[]记录_数组=新结构[2];
对于(int i=0;i<2;i++){
结构oracle_记录=新结构(recDescriptor,conn,new
对象[]{i,“test”});
记录\u数组[i]=oracle\u记录;
}
CallableStatement stmt=conn.prepareCall(“{call TEST.TEST_FUNC(?,?)}”);
ArrayDescriptor ArrayDescriptor=ArrayDescriptor.createDescriptor(“TEST.TESTARR\u T”,康涅狄格州);
数组oracle_数组=新数组(arrayDescriptor,conn,RECORDS_数组);
//绑定输入记录
stmt.setArray(1,oracle_数组);
stmt.registerOutParameter(2,类型.NUMERIC);
stmt.registerOutParameter(3,类型.NUMERIC);
stmt.executeUpdate();
double out1=stmt.getDouble(2);
double out2=stmt.getDouble(3);
返回新对象[]{out1,out2};
我刚刚读到oracle jdbc不支持pl/sql结构类型。因此,使用“无效的名称模式:test.testrec\r”会失败

如何从Java调用此过程?理想情况下,只使用JavaLibrary/API,但这似乎是不可能的,在简单的sql调用中封装pl/sql包并调用它的最佳解决方案是什么


另外,我正在使用Spring JDBCTemplate进行数据库连接。

您不能使用PL/SQL类型,因为它们仅为PL/SQL所知(因为12c不再严格适用于此-请参阅UPD)。此外,java无法直接看到在包中创建的任何类型。
您应该在架构级别创建SQL类型。SQL类型对所有人都可见,所有人都可以使用

create or replace and compile java source named "ArrayOfRecTest" as 
import java.io.*; 
import java.sql.*; 
import oracle.sql.*; 
import oracle.jdbc.driver.*; 

public class ArrayOfRecTest 
{ 
    public static void passArrayOfRec() throws SQLException 
    { 
        Connection conn = new OracleDriver().defaultConnection(); 

        StructDescriptor sd = StructDescriptor.createDescriptor("MYREC_TYPE", conn);
        ArrayDescriptor ad = ArrayDescriptor.createDescriptor("MYRECARR_TYPE", conn);
        STRUCT[] recarr = new STRUCT[2];
        for (int i = 0; i < 2; i++) { recarr[i] = new STRUCT(sd, conn, new Object[] {i+1, "value " + (i+1)}); }
        ARRAY oracle_array = new ARRAY(ad, conn, recarr);

        CallableStatement stmt = conn.prepareCall("{ ? = call testpkg.showArrOfRec(?, ?, ?) }");
        stmt.registerOutParameter(1, Types.INTEGER);
        stmt.setObject(2, oracle_array);
        stmt.registerOutParameter(3, Types.INTEGER);
        stmt.registerOutParameter(4, Types.INTEGER);

        stmt.execute();
        int sizeofArr = stmt.getInt(1);
        int total = stmt.getInt(3);
        int totalLength = stmt.getInt(4);
        System.out.println("passArrayOfRec(total,len)=(" + total + "," + totalLength + ") " + sizeofArr + " records were shown");
    }
}
/

create or replace force type myrec_type as object( id number, value varchar2(100));
/ 
create or replace type myrecarr_type as table of myrec_type;
/

create or replace package testpkg as
    procedure passArrayOfRec as language java name 'ArrayOfRecTest.passArrayOfRec()' ; 
    function showArrOfRec(ra myrecarr_type, total out number, totallength out number) return number;
end testpkg;
/

create or replace package body testpkg as 
    --OP stuff 
    type testrec_r is record (val1 number, val2 varchar2(100));
    type testarr_t is table of testrec_r index by binary_integer;
    function test_func(data in testarr_t, total out number, totallength out number) return number is
    begin
        <<for_each>> for i in data.first..data.last loop
            dbms_output.put_line('data(' || i || ')[val1,val2]=[' || data(i).val1 || ',' || data(i).val2 || ']');
            total := nvl(total,0) + data(i).val1;
            totallength := nvl(totallength,0) + length(data(i).val2);
        end loop for_each;
        return data.count;
    end test_func;
    --end OP stuff

    function showArrOfRec(ra myrecarr_type, total out number, totallength out number) return number is
        data testarr_t; 
    begin
        for i in ra.first..ra.last loop data(i).val1 := ra(i).id; data(i).val2 := ra(i).value; end loop; 
        return test_func(data, total, totalLength);
    end showArrOfRec;
end testpkg;
/

exec testpkg.passArrayOfRec;
创建或替换并编译名为“ArrayOfRecTest”的java源代码
导入java.io.*;
导入java.sql.*;
导入oracle.sql.*;
导入oracle.jdbc.driver.*;
公共类ArrayOfRecTest
{ 
public static void passArrayOfRec()引发SQLException
{ 
连接连接=新的OracleDriver().defaultConnection();
StructDescriptor sd=StructDescriptor.createDescriptor(“MYREC_类型”,conn);
ArrayDescriptor ad=ArrayDescriptor.createDescriptor(“MYRECARR_类型”,conn);
STRUCT[]recarr=新结构[2];
对于(inti=0;i<2;i++){recarr[i]=new STRUCT(sd,conn,new Object[]{i+1,“value”+(i+1)};}
阵列oracle_阵列=新阵列(ad、conn、recarr);
CallableStatement stmt=conn.prepareCall(“{调用testpkg.showArrOfRec(?,?)}”);
stmt.registerOutParameter(1,Types.INTEGER);
stmt.setObject(2,oracle_数组);
stmt.registerOutParameter(3,Types.INTEGER);
stmt.registerOutParameter(4,Types.INTEGER);
stmt.execute();
int sizeofar=stmt.getInt(1);
int total=stmt.getInt(3);
int totalength=stmt.getInt(4);
System.out.println(“显示了passArrayOfRec(总计,len)=(“+total+”,“+totalLength+”)“+sizeofArr+”记录);
}
}
/
创建或替换强制类型myrec_type作为对象(id号,值varchar2(100));
/ 
创建或替换类型myrecarr_type作为myrec_type的表;
/
创建或替换包testpkg作为
过程PassarArrayOfrec作为语言java名称'ArrayOfRecTest.PassarArrayOfrec()';
函数showArrOfRec(ra myrecarr_类型、总输出编号、总长度输出编号)返回编号;
结束测试包;
/
创建或替换包体testpkg作为
--OP材料
类型testrec_r为记录(val1编号,val2 varchar2(100));
类型testarr\u t是由二进制整数组成的testrec\r索引表;
函数测试函数(测试中的数据、总输出数、总长度输出数)返回数为
开始
对于数据中的i.first..data.last循环
dbms|u output.put|u line('data('i | | | |')[val1,val2]=['i | | data(i).val1 | |','i | data(i).val2 | |');
总计:=nvl(总计,0)+数据(i)。val1;
总长度:=nvl(总长度,0)+长度(数据(i).val2);
每个_的结束循环;
返回数据.count;
结束测试_func;
--最后的东西
函数showArrOfRec(ra myrecarr_类型、总输出编号、总长度输出编号)返回编号为
数据测试;
开始
对于ra.first..ra.last循环数据中的i(i).val1:=ra(i).id;数据(i).val2:=ra(i).值;端环;
返回测试函数(数据、总长度、总长度);
弗雷克终点;
结束测试包;
/
exec testpkg.passArrayOfRec;
输出:

数据(1)[val1,val2]=[1,值1]
数据(2)[val1,val2]=[2,值2]
显示了passArrayOfRec(总计,len)=(3,14)2条记录



UPD

@csm86此函数应返回什么?在你的问题中,我看不出函数的作用。对不起,我错误地删除了最后一条评论。这是一个伪函数,返回数组的长度,并在输出参数中输出数字和字符串的总长度。这就是我想在简单sql中得到的。@csm86好的,我用函数调用更新了它。总数应该不是什么大问题。谢谢你的提示。但你还是不明白我的问题。我想将myrec_类型转换为testrec_r,并使用这种参数调用test.test_func(来自我的示例)。不要重写plsql功能。我可能想使用复杂的逻辑。所以我认为主要的问题是从sql类型到plsql类型的双向转换。@csm86在plsql上下文中的类型转换根本没有问题。这只是一个循环。您可以使用参数中的sql类型编写包装过程或函数,并在其中执行类型转换。而不是直接从java调用这个wrap函数。这能解决你的问题吗?