Java - передача массива в хранимую процедуру оракула

У меня есть приложение Java, обращающееся к хранимой процедуре оракула. Аргументы хранимой процедуры включают тип массива. Я делаю это следующим образом...

con = this._getConnection();  
Connection narrowdConn = (Connection)WSJdbcUtil.getNativeConnection( (WSJdbcConnection)con );  

callable = con.prepareCall("{call MY_PKG.MY_PROCEDURE(?, ?)}");  


ArrayDescriptor arrayDescriptor = ArrayDescriptor.createDescriptor("VARCHAR2_ARR", narrowdConn);  
ARRAY arrayArg1 = new ARRAY(arrayDescriptor, con, docNames);  
ARRAY arrayArg2 = new ARRAY(arrayDescriptor, con, docTypes);  

callable.setArray(1, arrayArg1);  
callable.setArray(2, arrayArg2);  

callable.execute();  

Теперь я получаю это исключение...

java.sql.SQLException: invalid name pattern: MY_PKG.VARCHAR2_ARR

VARCHAR2_ARR является общедоступным TYPE, определенным внутри пакета Oracle, как показано ниже:

ТИП VARCHAR2_ARR - ТАБЛИЦА VARCHAR2(50);

И используется как таковой в моей хранимой процедуры...

PROCEDURE MY_PROCEDURE  
    (V_ARR_ARG1  IN VARCHAR2_ARR,  
     V_ARR_ARG2  IN VARCHAR2_ARR)  

3 ответа

Тип VARCHAR2_ARR это тип PLSQL, вы не сможете напрямую связать его с Java. Я предлагаю вам заглянуть в эту ветку на AskTom относительно аналогичного вопроса.

Вот пара предложений:

  • создать тип SQL, который вы можете связать с Java
  • вставить во временную таблицу из Java и читать из него в PLSQL

В обоих случаях вам придется либо изменить процедуру PLSQL, либо добавить новую процедуру перевода.

Я застрял на этой проблеме. Надеюсь, эта иллюстрация поможет вам:

Шаги по созданию процедуры в oracle.

  • Создайте тип желаемого объекта как:
      CREATE OR REPLACE TYPE STUDENT_TYPE IS OBJECT
( ID NUMBER,
  NAME VARCHAR2(50));
  • Создайте еще один объект массива как:
      CREATE OR REPLACE TYPE STUDENT_ARRAY IS TABLE OF STUDENT_TYPE;
  • Создайте процедуру для приема массива объектов и выполните желаемую операцию, здесь я просто вставляю записи в таблицу как:
      CREATE OR REPLACE PROCEDURE SP_INSERT_STUDENT_RECORD_IN_BULK(
IN_STUDENT_RECORDS STUDENT_ARRAY) IS
BEGIN 
  FOR i IN IN_STUDENT_RECORDS.first.. IN_STUDENT_RECORDS.last
   LOOP
    BEGIN 
      INSERT INTO STUDENT(ID,NAME) VALUES
      (IN_STUDENT_RECORDS(i).ID, IN_STUDENT_RECORDS(i).NAME)
    END;
   END LOOP:
END SP_INSERT_STUDENT_RECORD_IN_BULK;

Фрагмент кода для вызова процедуры через Java

      import org.springframework.jdbc.core.*;
import oracle.jdbc.OracleConnection;
....
List<Student> students = getStudentList();
try(Connection hikariCon = dataSource.getConnection()){
    if(hikariCon.isWrapperFor(OracleConnection.class)){
        OracleConnection con = hikariCon.unwrap(OracleConnection.class);
        Object[] students = students.stream().map(student -> {
            return con.createStruct(STUDENT_TYPE, new Object[]{
                student.getId(),
                student.getName()
            });
        }).collect(Collectors.list()).flatMap(List::stream).toArray();
        
        SimpleJdbcCall jdbcCall = new SimpleJdbcCall(dataSource)
                                .withProcedureName("SP_INSERT_STUDENT_RECORD_IN_BULK")
                                .declareParameters(
                                new SqlParameter("IN_STUDENT_RECORDS", Types.ARRAY));
        jdbcCall.execute(con.createOracleArray(STUDENT_ARRAY,students))
    }
} catch(Exception e){
    log.error("Error due to- {}",e,getMessage());
}

Нам нужно установить accessToUnderlyingConnectionAllowed falg true при создании источника данных

Другие вопросы по тегам