Вызов хранимой процедуры Oracle из JDBC со сложным типом ввода и вывода - PullRequest
5 голосов
/ 10 февраля 2012

Я так близок к решению этого вопроса, но я явно что-то упускаю. Мое требование - вызвать хранимую процедуру в Oracle из JDBC. Хранимая процедура принимает 1 пользовательский объект Oracle в качестве INput и другой пользовательский объект Oracle в качестве OUTput. Объекты INput и OUTput имеют смесь как примитивных типов данных Oracle, так и коллекции другого набора пользовательских объектов. Я успешно могу вызвать хранимую процедуру и получить результаты обратно, пока я установил NULL для типов коллекций в объектах INput и OUTput. Если я пытаюсь создать ArrayDescriptor для списка объектов Oracle, чтобы отправить его в хранимую процедуру, я продолжаю сталкиваться с препятствиями. Поэтому мне нужна помощь в выяснении, как установить Array для объекта INput и установить для него CallableStatement. Обратите внимание, я знаю, как я могу отправить тип и массив примитива в качестве прямого ввода в хранимую процедуру. Но я не хочу идти по этому пути, так как позже мы должны отправить 10 дополнительных полей в процедуру, я не хочу добавлять их в сигнатуру метода. Вот список классов. Кроме того, нет ошибок компиляции для кода ниже.

Пакет в оракуле:

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 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;

Часть объекта UserDefined объекта INput :

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.

1 Ответ

0 голосов
/ 21 января 2013

Это очень старый подход, почему вы не используете "Oradata" и "Oradatum" интерфейс? Это сэкономит много усилий.

Ваш подход оставляет много ошибок для ошибок, вам придется правильно читать поток и проверять порядок полей самостоятельно, что может быть сложно. Подход Oradata сделает это за вас.

Исходя из вашего подхода, ваш код не очень понятен. Но просто для краткого обзора, StructDescriptor будет сопоставляться с типом записи Oracle, а ArrayDescriptor будет сопоставляться с типом таблицы Oracle, из вашего кода я не понимаю, чего вы пытаетесь достичь.

Я могу помочь, если вы можете сделать это более ясным.

...