【问题标题】:The stored procedure call with cursors throws invalid column name exception带游标的存储过程调用抛出无效列名异常
【发布时间】:2020-06-12 04:59:53
【问题描述】:

我们有一个 Spring Boot 应用程序,我们需要连接到 Oracle DB 并通过存储过程获取数据。我们的每个存储过程都有REF_CURSOR 作为OUT 参数。我正在尝试使用@NamedStoredProcedureQuery@Entity 注释。我们在pom.xml 中使用ojdbc14.jar,在application.properties 文件中使用Oracle12cDialect。我在执行我的代码时收到异常Invalid Column Name。同样在实体类中,我必须引入一个带有注释@Id 的字段,尽管我的存储过程的REF_CURSOR 没有返回这样的字段。这会是个问题吗?同样不定义 @Id 字段也不是一个选项,因为 Hibernate 会抛出异常。任何提示将不胜感激。

实现和问题与问题非常相似 Invalid column name exception when calling an Oracle stored procedure with ref_cursor through JPA 2.1

但是那里没有发布答案

【问题讨论】:

  • 如果你想让我们告诉你为什么它会抛出异常,你需要包含你正在执行的代码(以及相关的东西,比如你的实体类)。
  • 其实这违反了公司政策,所以我不能发布代码。但是,如果您想查看任何特定的代码,请告诉我。然后我可以发布一些演示实现。
  • 实现&问题与以下链接stackoverflow.com/questions/39752658/…非常相似
  • @LearningJava 很高兴看到您的存储过程的合同(一些显示重要/有问题部分的简化版本)和适当的实体部分。
  • @StemK - 过程 proc_name(nvarcharr2 中的 p_in_param1,sys_refcursor 中的 p_out_list)。希望这份合同有所帮助。

标签: oracle hibernate cursors spring-boot-jpa


【解决方案1】:

如何实现它的简单示例:

  1. 数据库架构。
create table MY_PATIENT
(
   PAT_RECID  number,
   PAT_NAME varchar2(100),
   
   constraint PAT_PK primary key(PAT_RECID)
);

create table MY_ORDER
(
   ORD_RECID  number,
   ORD_CODE varchar2(15),
   ORD_PATID number,
   
   constraint ORD_PK primary key(ORD_RECID),
   constraint ORD_PAT_FK foreign key(ORD_PATID) references MY_PATIENT(PAT_RECID),
   constraint ORD_CODE_UNIQUE unique (ORD_CODE)
);

CREATE OR REPLACE PROCEDURE fetch_patient_orders(
  patientId IN NUMBER, 
  patientOrders OUT SYS_REFCURSOR)
AS
BEGIN
   OPEN patientOrders FOR
   SELECT *
   FROM MY_ORDER
   WHERE ORD_PATID = patientId;
END;
  1. 实体定义。
@NamedStoredProcedureQueries(
   @NamedStoredProcedureQuery(
      name = "fetch_patient_orders",
      procedureName = "fetch_patient_orders",
      resultClasses = Order.class, 
      parameters = {
         @StoredProcedureParameter(
            name = "patientId",
            type = Long.class,
            mode = ParameterMode.IN
         ),
         @StoredProcedureParameter(
            name = "patientOrders",
            type = Class.class,
            mode = ParameterMode.REF_CURSOR
         )
      }
   )
)
@Entity
@Table(name = "MY_ORDER")
public class Order
{
   @Id
   @Column(name = "ORD_RECID")
   private Long id;
   
   @Column(name = "ORD_CODE")
   private String code;

   @ManyToOne
   @JoinColumn(name = "ORD_PATID")
   private Patient patient;
}
  1. 及用法:
List<Order> orders = session.createNamedStoredProcedureQuery("fetch_patient_orders")
    .setParameter("patientId", 2L)
    .getResultList();

已使用 hibernate 5.4.12.Final、ojdbc8.jarOracle12cDialect 进行了测试。 另见休眠documentation

上述方法适用于纯休眠应用程序,但不适用于 Spring Boot 应用程序。

根据弹簧靴documentation

连接到生产数据库

生产数据库连接也可以通过使用池DataSource 自动配置。 Spring Boot 使用以下算法来选择特定的实现:

  1. 我们更喜欢 HikariCP 的性能和并发性。如果 HikariCP 可用,我们总是选择它。

  2. 否则,如果 Tomcat 池化 DataSource 可用,我们就使用它。

  3. 如果 HikariCP 和 Tomcat 池数据源都不可用,并且如果 Commons DBCP2 可用,我们使用它。

如果您使用 spring-boot-starter-jdbcspring-boot-starter-data-jpa “starters”,您将自动获得对 HikariCP 的依赖。

您可以完全绕过该算法并通过设置spring.datasource.type 属性来指定要使用的连接池。

所以,spring boot 默认使用 HikariCP JDBC 连接池。而且貌似REF_CURSOR参数注册有问题:

o.h.r.j.i.ResourceRegistryStandardImpl   : Registering statement [HikariProxyCallableStatement@770201936 wrapping oracle.jdbc.driver.OracleCallableStatementWrapper@528a6369]
o.h.type.descriptor.sql.BasicBinder      : binding parameter [patientId] as [BIGINT] - [2]
o.h.s.i.AbstractServiceRegistryImpl      : Initializing service [role=org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport]
o.h.engine.jdbc.spi.SqlExceptionHelper   : Error registering REF_CURSOR parameter [patientOrders] [n/a]

当我使用application.properties中的oracle特定数据源池时:

# com.zaxxer.hikari.HikariDataSource (default value)
spring.datasource.type=oracle.jdbc.pool.OracleDataSource

一切正常。

【讨论】:

  • 不幸的是,我的是一个 Spring Boot 应用程序
猜你喜欢
  • 2023-03-05
  • 1970-01-01
  • 1970-01-01
  • 2016-07-29
  • 2022-01-23
  • 2012-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多