简体   繁体   English

从Spring JDBC使用PL / SQL记录类型调用Oracle过程

[英]Calling Oracle procedure with PL/SQL record Type from Spring JDBC

I'm trying to call Oracle procedure with one IN parameter which has PL/SQL Record type. 我试图用一个具有PL / SQL记录类型的IN参数调用Oracle过程。

I wrote a following code: 我写了下面的代码:

SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbcTemplate).withProcedureName("P_INSERTCLIENT");
jdbcCall.declareParameters(new SqlParameter("V_CLIENT_RECORD", OracleTypes.ARRAY));

MapSqlParameterSource in = new MapSqlParameterSource().addValue("V_CLIENT_RECORD", client);

jdbcCall.execute(in);

When I execute the code I get a following error: 当我执行代码时,出现以下错误:

java.sql.SQLException: Fail to convert to internal representation: com.my.test.resource.model.Client@5df613a2

I wonder is it possible to call a procedure with IN parameter defined as PL/SQL Record and how to do it? 我想知道是否可以使用定义为PL / SQL Record的IN参数来调用过程,该怎么做?

I don't think you can use OracleTypes.Array since it's a record. 我认为您无法使用OracleTypes.Array,因为它是记录。

https://docs.oracle.com/cd/E11882_01/java.112/e16548/apxref.htm#JJDBC28928 https://docs.oracle.com/cd/E11882_01/java.112/e16548/apxref.htm#JJDBC28928

PL/SQL TABLE, BOOLEAN, and RECORD Types PL / SQL TABLE,BOOLEAN和RECORD类型

It is not feasible for Oracle JDBC drivers to support calling arguments or return values of the PL/SQL RECORD, BOOLEAN, or table with non-scalar element types. Oracle JDBC驱动程序不支持调用参数或具有非标量元素类型的PL / SQL RECORD,BOOLEAN或表的返回值是不可行的。 However, Oracle JDBC drivers support PL/SQL index-by table of scalar element types. 但是,Oracle JDBC驱动程序支持标量元素类型的PL / SQL索引表。

See Also: 也可以看看:

"Accessing PL/SQL Index-by Tables" “访问PL / SQL索引表”

As a workaround to PL/SQL RECORD, BOOLEAN, or non-scalar table types, create container procedures that handle the data as types supported by JDBC. 作为PL / SQL RECORD,BOOLEAN或非标量表类型的解决方法,创建容器过程以将数据作为JDBC支持的类型进行处理。 For example, to wrap a stored procedure that uses PL/SQL boolean, create a stored procedure that takes a character or number from JDBC and passes it to the original procedure as BOOLEAN or, for an output parameter, accepts a BOOLEAN argument from the original procedure and passes it as a CHAR or NUMBER to JDBC. 例如,要包装使用PL / SQL布尔值的存储过程,请创建一个存储过程,该存储过程从JDBC获取一个字符或数字,并将其作为BOOLEAN传递给原始过程,或者对于输出参数,从原始输入接受BOOLEAN参数。过程并将其作为CHAR或NUMBER传递给JDBC。 Similarly, to wrap a stored procedure that uses PL/SQL records, create a stored procedure that handles a record in its individual components, such as CHAR and NUMBER, or in a structured object type. 同样,要包装使用PL / SQL记录的存储过程,请创建一个存储过程,以其单个组件(例如CHAR和NUMBER)或结构化对象类型来处理记录。 To wrap a stored procedure that uses PL/SQL tables, break the data into components or perhaps use Oracle collection types. 要包装使用PL / SQL表的存储过程,请将数据分解为组件,或者也许使用Oracle集合类型。

Unfortunately, the Oracle JDBC driver doesn't provide access to the PL/SQL RECORD type, neither for IN nor for OUT parameters. 不幸的是,Oracle JDBC驱动程序不提供对PL / SQL RECORD类型的访问,无论是IN参数还是OUT参数。

Workaround for a single procedure call: 单个过程调用的解决方法:

But you can work around this limitation by using an anonymous PL/SQL block in JDBC (or Spring JDBC) directly: 但是您可以通过直接在JDBC(或Spring JDBC)中使用匿名PL / SQL块来解决此限制:

DECLARE
  rec MY_PACKAGE.MY_RECORD;
BEGIN

  -- Replace these by your actual record attributes:
  rec.first_name := ?;
  rec.last_name := ?;
  ...

  p_insertclient(rec);
END;

This works perfectly fine for a single procedure call. 对于单个过程调用,这工作得很好。

Solid solution for many of these calls: 这些调用的可靠解决方案:

If you do the above quite frequently, it's worth generating stubs that produce the anonymous PL/SQL strings automatically, rather than writing those manually all the time. 如果您经常执行上述操作,则值得生成存根以自动生成匿名PL / SQL字符串,而不是一直手动编写。 You can automatically discover all the PL/SQL RECORD types in your schema with the following query: 您可以使用以下查询自动发现架构中的所有PL / SQL RECORD类型:

SELECT
  x.TYPE_OWNER, x.TYPE_NAME, x.TYPE_SUBNAME, a.ARGUMENT_NAME ATTR_NAME,
  a.SEQUENCE ATTR_NO, a.TYPE_OWNER ATTR_TYPE_OWNER,
  nvl2(a.TYPE_SUBNAME, a.TYPE_NAME, NULL) package_name,
  COALESCE(a.TYPE_SUBNAME, a.TYPE_NAME, a.DATA_TYPE) ATTR_TYPE_NAME,
  a.DATA_LENGTH LENGTH, a.DATA_PRECISION PRECISION, a.DATA_SCALE SCALE
FROM SYS.ALL_ARGUMENTS a
JOIN (
  SELECT
    a.TYPE_OWNER, a.TYPE_NAME, a.TYPE_SUBNAME,
    MIN(a.OWNER) KEEP (DENSE_RANK FIRST ORDER BY a.OWNER ASC, a.PACKAGE_NAME ASC, a.SUBPROGRAM_ID ASC, a.SEQUENCE ASC) OWNER,
    MIN(a.PACKAGE_NAME) KEEP (DENSE_RANK FIRST ORDER BY a.OWNER ASC, a.PACKAGE_NAME ASC, a.SUBPROGRAM_ID ASC, a.SEQUENCE ASC) PACKAGE_NAME,
    MIN(a.SUBPROGRAM_ID) KEEP (DENSE_RANK FIRST ORDER BY a.OWNER ASC, a.PACKAGE_NAME ASC, a.SUBPROGRAM_ID ASC, a.SEQUENCE ASC) SUBPROGRAM_ID,
    MIN(a.SEQUENCE) KEEP (DENSE_RANK FIRST ORDER BY a.OWNER ASC, a.PACKAGE_NAME ASC, a.SUBPROGRAM_ID ASC, a.SEQUENCE ASC) SEQUENCE,
    MIN(next_sibling) KEEP (DENSE_RANK FIRST ORDER BY a.OWNER ASC, a.PACKAGE_NAME ASC, a.SUBPROGRAM_ID ASC, a.SEQUENCE ASC) next_sibling,
    MIN(a.DATA_LEVEL) KEEP (DENSE_RANK FIRST ORDER BY a.OWNER ASC, a.PACKAGE_NAME ASC, a.SUBPROGRAM_ID ASC, a.SEQUENCE ASC) DATA_LEVEL
  FROM (
    SELECT
      lead(a.SEQUENCE, 1, a.SEQUENCE) OVER (
        PARTITION BY a.OWNER, a.PACKAGE_NAME, a.SUBPROGRAM_ID, a.DATA_LEVEL
        ORDER BY a.SEQUENCE ASC
      ) next_sibling,
      a.TYPE_OWNER, a.TYPE_NAME, a.TYPE_SUBNAME, a.OWNER, a.PACKAGE_NAME, 
      a.SUBPROGRAM_ID, a.SEQUENCE, a.DATA_LEVEL, a.DATA_TYPE
    FROM SYS.ALL_ARGUMENTS a
    WHERE a.OWNER IN ('MY_SCHEMA')     -- Possibly replace schema here
    ) a
  WHERE (a.TYPE_OWNER IN ('MY_SCHEMA') -- Possibly replace schema here
  AND a.OWNER         IN ('MY_SCHEMA') -- Possibly replace schema here
  AND a.DATA_TYPE      = 'PL/SQL RECORD')
  GROUP BY a.TYPE_OWNER, a.TYPE_NAME, a.TYPE_SUBNAME
  ) x
ON ((a.OWNER, a.PACKAGE_NAME, a.SUBPROGRAM_ID) = ((x.OWNER, x.PACKAGE_NAME, x.SUBPROGRAM_ID))
AND a.SEQUENCE BETWEEN x.SEQUENCE AND next_sibling
AND a.DATA_LEVEL = (x.DATA_LEVEL + 1))
ORDER BY x.TYPE_OWNER ASC, x.TYPE_NAME ASC, x.TYPE_SUBNAME ASC, a.SEQUENCE ASC

See more details about this technique in this blog post (from which the query was taken) . 在此博客文章(从中进行查询)中了解有关此技术的更多详细信息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从0jdbc6 JDBCthin驱动程序调用带有自定义对象的Oracle PL / SQL过程返回类型 - Calling an Oracle PL/SQL procedure with Custom Object return types from 0jdbc6 JDBCthin drivers 使用PL SQL表类型的参数对Oracle存储过程进行JDBC调用 - JDBC Call to Oracle Stored Procedure with parameters of type PL SQL table Oracle PL / SQL存储过程中的JDBC结果集 - JDBC result set from an Oracle PL/SQL stored procedure 使用JDBC以用户定义的记录作为其IN参数调用PL / SQL过程 - Calling PL/SQL procedure with user defined record as its IN parameter using JDBC 在Oracle PL / SQL中调用存储过程 - Calling Stored Procedure in Oracle PL/SQL 使用JDBC从Java调用Oracle SQL中的存储过程的示例 - Example for calling a stored procedure in Oracle SQL from Java using JDBC 从Spring Boot调用Oracle PL / SQL函数时出错 - Error while calling an Oracle PL/SQL function from Spring Boot 使用JDBC将SYS_REFCURSOR作为IN参数调用PL / SQL过程 - Calling PL/SQL procedure with SYS_REFCURSOR as IN parameter using JDBC {Spring的Java核心}通过纯JDBC调用PL SQL存储过程-理想情况下,谁应该执行事务管理 - {Core Java with Spring} calling PL SQL stored procedure via plain JDBC - who should ideally do transaction management Oracle JDBC / PL SQL / TYPE /包级别/无效的名称模式 - Oracle JDBC / PL SQL / TYPE / Package Level / Invalid Name Pattern
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM