从Spring JDBC使用PL/SQL记录类型调用Oracle过程 [英] Calling Oracle procedure with PL/SQL record Type from Spring JDBC

查看:57
本文介绍了从Spring JDBC使用PL/SQL记录类型调用Oracle过程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用一个具有PL/SQL记录类型的IN参数调用Oracle过程.

I'm trying to call Oracle procedure with one IN parameter which has PL/SQL Record type.

我编写了以下代码:

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

我想知道是否可以使用定义为PL/SQL Record的IN参数调用过程,以及如何实现?

I wonder is it possible to call a procedure with IN parameter defined as PL/SQL Record and how to do it?

推荐答案

不幸的是,Oracle JDBC驱动程序不提供对PL/SQL RECORD 类型的访问,对于 IN OUT 参数.

Unfortunately, the Oracle JDBC driver doesn't provide access to the PL/SQL RECORD type, neither for IN nor for OUT parameters.

但是您可以通过在JDBC(或Spring JDBC)中直接使用匿名PL/SQL块来解决此限制:

But you can work around this limitation by using an anonymous PL/SQL block in JDBC (or Spring JDBC) directly:

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.

如果您经常执行上述操作,则值得生成存根以自动生成匿名PL/SQL字符串,而不是始终手动编写.您可以使用以下查询自动发现架构中的所有PL/SQL RECORD 类型:

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. You can automatically discover all the PL/SQL RECORD types in your schema with the following query:

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).

这篇关于从Spring JDBC使用PL/SQL记录类型调用Oracle过程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆