2012-02-10 78 views
4

我非常接近解决这个问题,但我显然缺少一些东西。我的要求是从JDBC调用Oracle中的存储过程。存储过程将1个用户定义的Oracle对象作为INput,另一个用户定义的Oracle对象作为OUTput。 INput和OUTput对象混合使用原始Oracle数据类型和另一组用户定义对象的集合。只要我为INput和OUTput对象中的集合类型设置NULL,我就可以成功调用存储过程并返回结果。如果我尝试为Oracle对象列表创建ArrayDescriptor以将其发送到存储过程,我不断碰到障碍。所以我需要帮助解决如何将数组设置为INput对象并将其设置为CallableStatement。请注意,我知道如何将原始类型和数组作为直接输入发送到存储过程。但我不想这样做,因为我们稍后必须向过程发送10个附加字段,我不想将它们添加到方法签名中。这是类的列表。此外,下面的代码没有编译错误。从复杂的输入输出类型JDBC调用Oracle存储过程

包装在Oracle:

CREATE OR REPLACE TYPE TESTDATA_IN_OBJ AS OBJECT(
testStr1   VARCHAR2(5), 
arrObj1    ARR_OBJ_1_NT); 

阵列对象作为输入对象的一部分::

create or replace TYPE  ARR_OBJ_1_NT AS TABLE OF ARR_OBJ_1_OBJ; 
存储过程

CREATE OR REPLACE PACKAGE testPkg AS 
PROCEDURE spGetTestData (
TESTDATA_IN    IN   TESTDATA_IN_OBJ, 
TESTDATA_OUT  OUT    TESTDATA_OUT_OBJ 
); 
END; 

输入对象

输入对象的用户自定义的对象部分:

CREATE OR REPLACE TYPE ARR_OBJ_1_OBJ AS OBJECT 
(
teststr   VARCHAR2(14), 
testNumber NUMBER(4), 
); 

TestDataINObj.java:

import java.sql.Array; 
    import java.sql.SQLData; 
    import java.sql.SQLException; 
    import java.sql.SQLInput; 
    import java.sql.SQLOutput; 

    public class TestDataINObj implements SQLData 
    { 
private String sql_type = "TESTDATA_IN_OBJ"; 

protected String testStr1; 
protected Array arrObj1; 

@Override 
public String getSQLTypeName() throws SQLException 
{ 
    return this.sql_type; 
} 


    // getter and setter for fields 

@Override 
public void readSQL(SQLInput stream, String typeName) throws SQLException 
{ 
this.sql_type=typeName; 
    this.testStr1 = stream.readString(); 
    this.arrObj1 = stream.readArray(); 
} 

@Override 
public void writeSQL(SQLOutput stream) throws SQLException 
{ 
    stream.writeString(this.testStr1); 
    stream.writeArray(this.arrObj1); 
} 
    } 

TestDataINObjConverter.java

public class TestDataINObjConverter 
    { 
    public static TestDataINObj convertPOJOToDBInObj(Connection connection) 
     throws SQLException 
    { 
    TestDataINObj testDataINObj = new TestDataINObj(); 
     testDataINObj.setTestStr1("some string"); 
     ArrObj1NT[] ArrObj1NTList = ArrObj1NTConverter.convertPOJOToDBObj(); // this will return Java array of ArrObj1NT class 
     testDataINObj.setArrObj1(getOracleArray("ARR_OBJ_1_NT",connection, ArrObj1NTList)); 
    return testDataINObj; 
} 


private static Array getOracleArray(final String typeName, Connection connection, ArrObj1NT[] ArrObj1NTList) throws SQLException 
{ 
    if (typeName == null) 
    { 
     return null; 
    } 
    Array oracleArray = new ARRAY(new ArrayDescriptor(typeName, connection), connection, ArrObj1NTList); 
    return oracleArray; 
} 

代码实际执行调用存储过程

... //code to get connection 
    ..// connection is of type T4CConnection 
    Map typeMap = connection.getTypeMap(); 
     typeMap.put("TESTDATA_IN_OBJ", TestDataINObj.class); 
     typeMap.put("TESTDATA_OUT_OBJ", TestDataOUTObj.class); 
     typeMap.put("ARR_OBJ_1_NT", ArrObj1NT.class); 

     TestDataINObj testDataINObj = TestDataINObjConverter.convertPOJOToDBInObj(connection); 

     getMetaDataCallableStatement = connection.prepareCall("begin " + "testPkg" + ".spGetTestData (?,?);"+ " end;"); 
     getMetaDataCallableStatement.setObject(1, testDataINObj); 
     getMetaDataCallableStatement.registerOutParameter(2, Types.STRUCT, "TESTDATA_OUT_OBJ"); 
     rs = getMetaDataCallableStatement.executeQuery(); 

     TestDataOUTObj testDataOUTObj = (TestDataOUTObj) getMetaDataCallableStatement.getObject(2, typeMap); 

其他: 1.对象是在模式级声明,可用于数据库用户访问它。 2.我没有在这里包含所有相应的Java对象,因为它需要更多的空间。他们实现SQLData接口,他们的类型名称与数据库名称匹配。 read和writeSQL方法使用getString,getArray和相应的setter方法。

+0

你正走向正确的道路。你能发布你得到的例外吗? – Nick 2012-05-29 17:50:31

+0

TESTDATA_OUT_OBJ声明在哪里? – Nagh 2012-08-13 01:22:34

+0

嘿,你有答案吗? – 2017-02-22 11:09:17

回答

0

这是一个非常古老的方法,为什么你不使用“Oradata”和“Oradatum”界面? 这将节省很多努力。

你的方法留下了很多scopr的错误,你将不得不以适当的方式阅读流,并检查自己的领域排序可能会非常棘手。 Oradata方法将为你做到这一点。

即将到来的方法,您的代码不是很清楚。 但是,只是为了给出一个概述,StructDescriptor将映射到oracle记录类型,并且ArrayDescriptor将映射到oracle表类型,从您的代码中我很困惑你正试图实现的。

我可以帮助,如果你可以更清楚。