在Java中使用Oracle Plsq索引表调用StoredProcedure:替代已弃用的set/getPlsqlIn



我试图调用一个简单的Oracle存储过程,它需要一个plsql-index表并返回一个plsql-index表作为OUT参数。我的旧方法工作得很好,但我使用的方法现在已经过时了。这是我以前的方法:

OracleConnection oracleConnection = connection.unwrap(OracleConnection.class);
CallableStatement callableStatement = oracleConnection.prepareCall("BEGIN STORED_PROC_IBT_PACKAGE.SIMPLE_INANDOUT_NUMBER_DEC(?,?); END;");
OracleCallableStatement oracleCallableStatement = callableStatement.unwrap(OracleCallableStatement.class);
BigDecimal[] input = new BigDecimal[] {BigDecimal.valueOf(1), BigDecimal.valueOf(2),BigDecimal.ZERO,BigDecimal.ZERO,BigDecimal.ZERO,BigDecimal.ZERO,BigDecimal.ZERO,
BigDecimal.ZERO,BigDecimal.ZERO,BigDecimal.ZERO};

oracleCallableStatement.setPlsqlIndexTable(1, input,10, input.length,Types.DECIMAL, 10);
oracleCallableStatement.registerIndexTableOutParameter(2, 10, Types.DECIMAL, 10);

oracleCallableStatement.execute();

BigDecimal[] plsqlIndexTable = (BigDecimal[])oracleCallableStatement.getPlsqlIndexTable(2);
Arrays.stream(plsqlIndexTable).forEach(System.out::println);

我不确定如果我的新方法是正确的使用数组和使用'setObject', 'getObject'和'createOracleArray',但它的工作几乎完美。我的新方法:

OracleConnection oracleConnection = connection.unwrap(OracleConnection.class);
CallableStatement callableStatement = oracleConnection.prepareCall("BEGIN STORED_PROC_IBT_PACKAGE.SIMPLE_INANDOUT_NUMBER_DEC(?,?); END;");
OracleCallableStatement oracleCallableStatement = callableStatement.unwrap(OracleCallableStatement.class);
BigDecimal[] input = new BigDecimal[] {BigDecimal.valueOf(1), BigDecimal.valueOf(2),BigDecimal.ZERO,BigDecimal.ZERO,BigDecimal.ZERO,BigDecimal.ZERO,BigDecimal.ZERO,
BigDecimal.ZERO,BigDecimal.ZERO,BigDecimal.ZERO};

oracleCallableStatement.setObject(1, oracleConnection.createOracleArray("DBACCESSTESTDB.STORED_PROC_IBT_PACKAGE.NUMBER_TABLE_INDEX", input));
oracleCallableStatement.registerOutParameter(2, Types.ARRAY, "DBACCESSTESTDB.STORED_PROC_IBT_PACKAGE.NUMBER_TABLE_INDEX");
oracleCallableStatement.execute();
Array plsqlIndexTable = (Array)oracleCallableStatement.getObject(2);
BigDecimal[] results = (BigDecimal[])plsqlIndexTable.getArray();
Arrays.stream(results).forEach(System.out::println);

新方法的问题是只有9个元素返回,而不是10个。原因可能是第一个元素(在Java中索引为0)在某个地方丢失了。我不知道它是否在发送到存储过程或检索它时丢失。这是一个Oracle Bug还是我的新方法是错误的?

编辑:好的,现在我知道问题发生时发送数组到storedProcedure。当我使用旧的方法setplsqlindextable;设置in参数和检索out参数的新方法('registerOutParameter'和'getObject')是有效的。但我仍然不知道如何解决这个问题。数组的第一个元素仍然丢失

好的,我想我找到问题了。我的存储过程是这样声明的:

PROCEDURE SIMPLE_INANDOUT_NUMBER_DEC
(
NUMBER_TABLE_INDEX_IN IN NUMBER_TABLE_INDEX,
NUMBER_TABLE_INDEX_OUT OUT NUMBER_TABLE_INDEX
)
AS
BEGIN
FOR i IN 1..NUMBER_TABLE_INDEX_IN.last  loop
NUMBER_TABLE_INDEX_OUT(i) := NUMBER_TABLE_INDEX_IN(i) + 1;
end loop;
END SIMPLE_INANDOUT_NUMBER_DEC;

对于旧的方法setPlSqlIndexTable,从索引1开始是正确的。从索引0开始将导致ORA_1403 No-Data.

使用新的方法('setObject' and 'createOracleArray'), PLSQL中的索引从0开始。因此,为了使它适用于两种方法,最好使用NUMBER_TABLE_INDEX_IN.first定义起始索引。

PROCEDURE SIMPLE_INANDOUT_NUMBER_DEC
(
NUMBER_TABLE_INDEX_IN IN NUMBER_TABLE_INDEX,
NUMBER_TABLE_INDEX_OUT OUT NUMBER_TABLE_INDEX
)
AS
BEGIN
FOR i IN NUMBER_TABLE_INDEX_IN.first..NUMBER_TABLE_INDEX_IN.last  loop
NUMBER_TABLE_INDEX_OUT(i) := NUMBER_TABLE_INDEX_IN(i) + 1;
end loop;
END SIMPLE_INANDOUT_NUMBER_DEC;

这是我发现的唯一一种方法,对我来说两种方法都适用。

最新更新