java—使用jdbc模板的简单jdbc调用调用oracle存储过程时面临的问题

pxq42qpu  于 2021-07-06  发布在  Java
关注(0)|答案(1)|浏览(425)

事实上,关于下面的问题,我已经耽搁了很长时间了。有没有人通过java实现了oracle存储过程调用,我实现了但是得到了下面的错误。

Exception occured in startAxonProducerProcess()","stack_trace":"org.springframework.jdbc.UncategorizedSQLException: CallableStatementCallback; uncategorized SQLException for SQL [{call POST_CYCLE_TFO_STAT_PKG.GET_CYCLE_EVNT_PAY_RECORDS(?, ?, ?, ?)}]; SQL state [99999]; error code [17068]; Invalid argument(s) in call; nested exception is java.sql.SQLException: Invalid argument(s) in call
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:89)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
    at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1443)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:1108)
    at org.springframework.jdbc.core.JdbcTemplate.call(JdbcTemplate.java:1147)
    at org.springframework.jdbc.core.simple.AbstractJdbcCall.executeCallInternal(AbstractJdbcCall.java:412)
    at org.springframework.jdbc.core.simple.AbstractJdbcCall.doExecute(AbstractJdbcCall.java:372)
    at org.springframework.jdbc.core.simple.SimpleJdbcCall.execute(SimpleJdbcCall.java:198)
    at  ...

我的过程语法是:-

PROCEDURE get_cycle_evnt_pay_records (
      RESULT_AXON_TB       OUT AXON_PAYMENT_TAB_T,
      ERROR_INFO           OUT VARCHAR2,
      RESULT               OUT BOOLEAN,
      DEBUG_FLAG        IN OUT BOOLEAN);
``` `AXON_PAYMENT_TAB_T` 属于类型 `TYPE AXON_PAYMENT_TAB_T IS TABLE OF AXON_PAYMENT_RECORDS_T;` 我的java代码是below:-

SimpleJdbcCall call1 = new SimpleJdbcCall(jdbcTemplate)
.withoutProcedureColumnMetaDataAccess()
.withProcedureName(GET_CYCLE_EVENT_PAY_RECORDS_PROCEDURE)
.declareParameters(new SqlOutParameter("RESULT_AXON_TB", Types.STRUCT))
.declareParameters(new SqlOutParameter("ERROR_INFO", Types.VARCHAR))
.declareParameters(new SqlOutParameter("RESULT", Types.BOOLEAN))
.declareParameters(new SqlParameter("DEBUG_FLAG", Types.BOOLEAN))
.declareParameters(new SqlOutParameter("DEBUG_FLAG", Types.BOOLEAN));

        SqlParameterSource in1 = new MapSqlParameterSource()
                .addValue("DEBUG_FLAG", true);

        Map<String, Object> result1 = call1.execute(in1);
任何人都可以分享一些关于这个问题的建议,关于这个问题,这将是非常有帮助的。
myzjeezk

myzjeezk1#

我会放弃使用springjdbc和 JdbcTemplate 调用这个存储过程,只需使用普通的jdbc。
问题不在于对象类型的表,而在于 OUT BOOLEAN 参数。这个 BOOLEAN jdbc不支持类型,所以我们必须解决它,而且这些解决方法不容易适应springjdbc。
我将使用以下代码:

String plsql =
            "DECLARE\n" +
            "  l_debug_flag     BOOLEAN;\n" +
            "  l_result         BOOLEAN;\n" +
            "BEGIN\n" +
            "  l_debug_flag := sys.diutil.int_to_bool(?);\n" +
            "  package_name_here.get_cycle_evnt_pay_records(?, ?, l_result, l_debug_flag);\n" +
            "  ? := sys.diutil.bool_to_int(l_result);\n" +
            "  ? := sys.diutil.bool_to_int(l_debug_flag);\n" +
            "END;";

    try (Connection connection = jdbcTemplate.getDataSource().getConnection()) {
        Map<String, Class<?>> typeMap = connection.getTypeMap();
        typeMap.put("AXON_PAYMENT_RECORDS_T", AxonPaymentRecords.class);
        connection.setTypeMap(typeMap);
        try (CallableStatement statement = connection.prepareCall(plsql)) {
            statement.setInt(1, 1); // The second 1 here corresponds to the 'true' value you set for DEBUG_FLAG
            statement.registerOutParameter(2, Types.ARRAY, "AXON_PAYMENT_TAB_T");
            statement.registerOutParameter(3, Types.VARCHAR);
            statement.registerOutParameter(4, Types.INTEGER);
            statement.registerOutParameter(5, Types.INTEGER);
            statement.execute();

            // Elements of this array should be AxonPaymentRecords instances.
            Object[] array = (Object[]) statement.getArray(2).getArray();

            String errorInfo = statement.getString(3);
            boolean result = (statement.getInt(4) == 1);
            boolean debugFlagOut = (statement.getInt(5) == 1);

            // do something with these values...
        }
    }

这在内置函数中使用了两个函数 DIUTIL 在布尔和数字之间转换的包,在 TRUE / FALSE / NULL 以及 1 / 0 / NULL 以显而易见的方式。我们不能用布尔值调用jdbc,所以我们传入和传出整数值,并在jdbc两边的布尔值和整数值之间进行转换。
您需要编写一个表示 AXON_PAYMENT_RECORDS_T 类型,它将需要实现 SQLData . 在上面的代码中我把它命名为 AxonPaymentRecords . 你需要实施 getSQLTypeName 以及 readSQL 方法 SQLData ,但除非您计划使用类型为的参数调用任何存储过程 AXON_PAYMENT_RECORDS_T 然后你就可以实现 writeSQL 投掷 UnsupportedOperationException 因为你不需要叫它。
oracle类型名出现在不同的地方:一次是添加到类型Map时,一次是注册表值输出参数时,一次是在的实现中 SQLData 我上面提到的。您可能需要用模式所有者限定这些类型名,如果它们是在包中声明的,还需要用包名限定它们(我猜它们是在一个包中声明的:在您的代码中不包括 CREATE OR REPLACE 在类型的定义中,以及 RECORDAXON_PAYMENT_RECORDS_T 使我怀疑这种类型是 RECORD 在一个包中,而不是一个 OBJECT 类似地,您可能还需要使用schema owner和/或包名限定存储过程的名称。
请注意,如果您使用的是oracle11g或更高版本,则不能使用包中声明的类型。我使用的是oracle18cxe,我让这段代码正常工作,尽管我必须编写类型的定义 AXON_PAYMENT_RECORDS_T 以及相关的java类。

相关问题