![](/img/trans.png)
[英]Issue while facing calling oracle stored procedure from Java using JDBC TEMPLATE
[英]Issue Facing in calling oracle stored procedure using Simple JDBC call of jdbc template
实际上,关于以下问题,我现在被困了很长时间。 有没有人通过 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
的类型为AXON_PAYMENT_TAB_T
是TYPE AXON_PAYMENT_TAB_T IS TABLE OF AXON_PAYMENT_RECORDS_T;
我的 Java 代码如下所示:-
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);
任何人都可以分享关于此问题的任何指示,这将非常有帮助。
我会放弃使用 Spring JDBC 和JdbcTemplate
来调用这个存储过程,而只使用普通的 JDBC。
问题不在于对象表类型,而在于OUT BOOLEAN
参数。 JDBC 不支持BOOLEAN
类型,因此我们必须解决它,而这些解决方法并不适合 Spring JDBC。
我会改用以下代码:
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
类型的 Java 类,并且它需要实现SQLData
。 在上面的代码中,我将其命名为AxonPaymentRecords
。 您将需要实现SQLData
的getSQLTypeName
和readSQL
方法,但除非您计划使用AXON_PAYMENT_RECORDS_T
类型的参数调用任何存储过程, AXON_PAYMENT_RECORDS_T
您可能可以实现writeSQL
以抛出UnsupportedOperationException
因为您不需要调用它。
Oracle 类型名称出现在不同的地方:一次是在添加到类型映射时,一次是在注册表值输出参数时,一次是在我上面提到的SQLData
的实现中。 您可能需要使用架构所有者来限定这些类型名称,如果它们在包中声明,还需要包名称。 (我猜它们是在一个包中声明的:在你的代码中,你没有在类型定义中包含CREATE OR REPLACE
,并且AXON_PAYMENT_RECORDS_T
中RECORD
的出现让我怀疑这个类型是一个包中的RECORD
,而不是在包外声明的OBJECT
。)同样,您可能还需要使用架构所有者和/或包名称来限定存储过程的名称。
请注意,如果您使用的是 Oracle 11g 或更早版本,您将无法使用在包中声明的类型。 我正在使用 Oracle 18c XE 并且我让这段代码正常工作,尽管我必须AXON_PAYMENT_RECORDS_T
类型的定义和关联的 Java 类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.