[英]Issue Facing in calling oracle stored procedure using Simple JDBC call of jdbc template
Actually I am stuck with quite a time now regarding the below issue.实际上,关于以下问题,我现在被困了很长时间。 Does anyone has implemented Oracle Stored procedure calling through Java, I have implemented but getting the below error.有没有人通过 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 ...
My procedure syntax is:-我的程序语法是:-
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
is of type TYPE AXON_PAYMENT_TAB_T IS TABLE OF AXON_PAYMENT_RECORDS_T;
AXON_PAYMENT_TAB_T
的类型为AXON_PAYMENT_TAB_T
是TYPE AXON_PAYMENT_TAB_T IS TABLE OF AXON_PAYMENT_RECORDS_T;
And my Java code is like below:-我的 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);
Can anyone share any pointers on this, regarding the issue, it will be really helpful.任何人都可以分享关于此问题的任何指示,这将非常有帮助。
I would give up on using Spring JDBC and a JdbcTemplate
to call this stored procedure, and just use plain JDBC.我会放弃使用 Spring JDBC 和JdbcTemplate
来调用这个存储过程,而只使用普通的 JDBC。
The problem isn't so much the table-of-object type, but the OUT BOOLEAN
parameters.问题不在于对象表类型,而在于OUT BOOLEAN
参数。 The BOOLEAN
type isn't supported by JDBC so we have to work around it, and these workarounds don't fit easily into Spring JDBC. JDBC 不支持BOOLEAN
类型,因此我们必须解决它,而这些解决方法并不适合 Spring JDBC。
I would use the following code instead:我会改用以下代码:
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...
}
}
This uses two functions in the built-in DIUTIL
package that convert between booleans and numbers, converting between TRUE
/ FALSE
/ NULL
and 1
/ 0
/ NULL
in the obvious way.这使用了内置DIUTIL
包中的两个函数,它们在布尔值和数字之间进行转换,以明显的方式在TRUE
/ FALSE
/ NULL
和1
/ 0
/ NULL
之间转换。 We can't call into JDBC with boolean values, so we pass integer values in and out, and convert between boolean and integer values on either side of JDBC.我们无法使用布尔值调用 JDBC,因此我们传入和传出整数值,并在 JDBC 的任一侧在布尔值和整数值之间进行转换。
You will need to write a Java class that represents your AXON_PAYMENT_RECORDS_T
type, and it will need to implementSQLData
.您将需要编写一个代表您的AXON_PAYMENT_RECORDS_T
类型的 Java 类,并且它需要实现SQLData
。 In the code above I named it AxonPaymentRecords
.在上面的代码中,我将其命名为AxonPaymentRecords
。 You will need to implement the getSQLTypeName
and readSQL
methods of SQLData
, but unless you are planning on calling any stored procedures with parameters of type AXON_PAYMENT_RECORDS_T
then you can probably implement writeSQL
to throw an UnsupportedOperationException
as you won't need to call it.您将需要实现SQLData
的getSQLTypeName
和readSQL
方法,但除非您计划使用AXON_PAYMENT_RECORDS_T
类型的参数调用任何存储过程, AXON_PAYMENT_RECORDS_T
您可能可以实现writeSQL
以抛出UnsupportedOperationException
因为您不需要调用它。
There are various places that Oracle type names appear: once when adding to the type map, once when registering the table-valued output parameter and once in the implementation of SQLData
that I mentioned above. Oracle 类型名称出现在不同的地方:一次是在添加到类型映射时,一次是在注册表值输出参数时,一次是在我上面提到的SQLData
的实现中。 You may need to qualify these type names with the schema owner, and also the package name if they are declared within a package.您可能需要使用架构所有者来限定这些类型名称,如果它们在包中声明,还需要包名称。 (I am guessing they are declared within a package: in your code you don't include CREATE OR REPLACE
in the definition of the type, and the appearance of RECORD
within AXON_PAYMENT_RECORDS_T
leads me to suspect that this type is a RECORD
within a package, rather than an OBJECT
declared outside a package.) Similarly, you may also need to qualify the name of the stored procedure with schema owner and/or package name. (我猜它们是在一个包中声明的:在你的代码中,你没有在类型定义中包含CREATE OR REPLACE
,并且AXON_PAYMENT_RECORDS_T
中RECORD
的出现让我怀疑这个类型是一个包中的RECORD
,而不是在包外声明的OBJECT
。)同样,您可能还需要使用架构所有者和/或包名称来限定存储过程的名称。
Note that if you are using Oracle 11g or older you won't be able to use types declared within a package.请注意,如果您使用的是 Oracle 11g 或更早版本,您将无法使用在包中声明的类型。 I'm using Oracle 18c XE and I got this code working, although I had to make up the definition of the type AXON_PAYMENT_RECORDS_T
and the associated Java class.我正在使用 Oracle 18c XE 并且我让这段代码正常工作,尽管我必须AXON_PAYMENT_RECORDS_T
类型的定义和关联的 Java 类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.