Вызов хранимой процедуры с курсорами вызывает исключение недопустимого имени столбца - PullRequest
1 голос
/ 28 февраля 2020

У нас есть приложение Spring Boot, где нам нужно подключиться к Oracle БД и получать данные с помощью хранимых процедур. Каждая из наших хранимых процедур имеет REF_CURSOR в качестве параметров OUT. Я пытаюсь сделать то же самое, используя аннотации @NamedStoredProcedureQuery и @Entity. Мы используем ojdbc14.jar в pom.xml и Oracle12cDialect в application.properties файле. Я получаю исключение Неверное имя столбца при выполнении моего кода. Также в классе сущностей я должен был ввести поле с аннотацией @Id, хотя такое поле не было возвращено REF_CURSOR моей хранимой процедуры. Может ли это быть проблемой? Также не указывается поле @Id, так как Hibernate выдает исключение. Любые советы будут высоко оценены.

Реализация и проблема очень похожи на вопрос Недопустимое исключение имени столбца при вызове хранимой процедуры Oracle с ref_cursor через JPA 2.1

Но там нет ответа

1 Ответ

0 голосов
/ 04 апреля 2020

Простой пример того, как этого добиться:

  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;
Определение сущности.
@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;
}
И использование:
List<Order> orders = session.createNamedStoredProcedureQuery("fetch_patient_orders")
    .setParameter("patientId", 2L)
    .getResultList();

Было протестировано с Hibernate 5.4.12.Final, ojdbc8.jar, Oracle12cDialect. См. Также документацию hibernate .

Описанный выше подход будет работать в чисто спящем приложении, но не в приложении весенней загрузки.

В зависимости от весенней загрузки документация :

Соединение с производственной базой данных

Соединения производственной базы данных также можно автоматически настраивать с помощью пула DataSource. Spring Boot использует следующий алгоритм выбора конкретной реализации c:

  1. Мы предпочитаем HikariCP за его производительность и параллелизм. Если HikariCP доступен, мы всегда выбираем его.

  2. В противном случае, если доступен источник данных Tomcat для пула, мы используем его.

  3. Если ни то, ни другое HikariCP и пул данных Tomcat доступны, и если Commons DBCP2 доступен, мы используем его.

Если вы используете стартеры spring-boot-starter-jdbc или spring-boot-starter-data-jpa ”, Вы автоматически получаете зависимость от HikariCP.

Вы можете полностью обойти этот алгоритм и указать используемый пул соединений, установив свойство spring.datasource.type.

Итак, весенняя загрузка по умолчанию использует пул соединений HikariCP JDB C. И похоже, что у него проблема с регистрацией параметров 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]

Когда я использую пул источника данных oracle Speci c в application.properties:

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

все отлично работает.

...