Хранимая процедура Exec не работает с JdbcCursorItemReader

#java #spring #jdbc #spring-batch #sybase

Вопрос:

Мне нужно считывать данные как из запросов select, так и из запросов exec Sybase с помощью JdbcCursorItemReader в Spring-Batch. В то время как запросы SELECT выполняются идеально, запросы Exec приводят к следующей ошибке:

Вызвано: org.springframework.jdbc.Исключение без категории SQLException: Выполнение запроса; исключение без категории SQLException для SQL [exec proc_1]; Состояние SQL [ZZZZZ]; код ошибки [7773]; Курсор выполнения «jconnect_implicit_1» объявлен в процедуре, которая содержит не-ВЫБОР или ВЫБОР с предложением COMPUTE. Чтобы объявление этого курсора было законным, в нем должен быть один оператор SELECT без предложения COMPUTE.

; вложенным исключением является исключение com.sybase.jdbc4.jdbc.SybSQLException: Выполнение курсора «jconnect_implicit_1» объявляется в процедуре, которая содержит предложение не SELECT или SELECT с предложением COMPUTE. Чтобы объявление этого курсора было законным, в нем должен быть один оператор SELECT без предложения COMPUTE. … опущено 43 общих фрейма

Вызвано: com.sybase.jdbc4.jdbc.SybSQLException: Курсор выполнения «jconnect_implicit_1» объявлен в процедуре, которая содержит не-SELECT или SELECT с предложением COMPUTE. Чтобы объявление этого курсора было законным, в нем должен быть один оператор SELECT без предложения COMPUTE.

… опущено 45 общих кадров

Код для JdbcCursorItemReader выглядит следующим образом:

 JdbcCursorItemReader itemReader = new JdbcCursorItemReader();
ColumnMapRowMapper rowMapper = new ColumnMapRowMapper();
itemReader.setDataSource(getDataSource());
itemReader.setRowMapper(rowMapper);
itemReader.setFetchSize(batchSize);
itemReader.setSql(dataSql); //datasql is passed Sybase query
 

Даже после использования программы StoredProcedureItemReader, как было предложено,
появляется следующая ошибка:

Вызвано: Исключение org.springframework.jdbc.UncategorizedSQLException: Выполнение хранимой процедуры; исключение SQLException без категории для SQL [{вызов ftsps_report(?, ?)}]; Состояние SQL [ZZZZZ]; код ошибки [7773]; Курсор выполнения «jconnect_implicit_1» объявлен в процедуре, которая содержит не-ВЫБОР или ВЫБОР с предложением ВЫЧИСЛЕНИЯ. Чтобы объявление этого курсора было законным, в нем должен быть один оператор SELECT без предложения COMPUTE.

; вложенным исключением является исключение com.sybase.jdbc4.jdbc.SybSQLException: Выполнение курсора «jconnect_implicit_1» объявляется в процедуре, которая содержит предложение не SELECT или SELECT с предложением COMPUTE. Чтобы объявление этого курсора было законным, в нем должен быть один оператор SELECT без предложения COMPUTE.

            at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:90)

           at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:82)

           at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:82)

           at org.springframework.batch.item.database.StoredProcedureItemReader.openCursor(StoredProcedureItemReader.java:226)

           at org.springframework.batch.item.database.AbstractCursorItemReader.doOpen(AbstractCursorItemReader.java:406)

           at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.open(AbstractItemCountingItemStreamItemReader.java:144)

           ... 43 common frames omitted
 

Вызвано: com.sybase.jdbc4.jdbc.SybSQLException: Курсор выполнения
«jconnect_implicit_1» объявлен в процедуре, которая содержит
не-SELECT или SELECT с предложением COMPUTE. Чтобы объявление
этого курсора было законным, в нем должен быть один оператор SELECT
без предложения COMPUTE.

            at com.sybase.jdbc4.tds.Tds.processEed(Tds.java:4112)

           at com.sybase.jdbc4.tds.Tds.nextResult(Tds.java:3229)

           at com.sybase.jdbc4.tds.Tds.getResultSetResult(Tds.java:3974)

           at com.sybase.jdbc4.tds.TdsCursor.open(TdsCursor.java:333)

           at com.sybase.jdbc4.jdbc.SybCallableStatement.sendRpc(SybCallableStatement.java:2032)

           at com.sybase.jdbc4.jdbc.SybCallableStatement.execute(SybCallableStatement.java:241)

           at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

           at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

           at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

           at java.lang.reflect.Method.invoke(Method.java:498)

           at org.apache.tomcat.jdbc.pool.StatementFacade$StatementProxy.invoke(StatementFacade.java:114)

           at com.sun.proxy.$Proxy83.execute(Unknown Source)

           at org.springframework.batch.item.database.StoredProcedureItemReader.openCursor(StoredProcedureItemReader.java:210)
 

Определили средство чтения StoredProcedureItemReader следующим образом:

 StoredProcedureItemReader itemReader = new StoredProcedureItemReader();
ColumnMapRowMapper rowMapper = new ColumnMapRowMapper();
itemReader.setDataSource(getDataSource());
itemReader.setRowMapper(rowMapper);
itemReader.setFetchSize(batchSize);
itemReader.setProcedureName(dataSql);
SqlParameter[] parameter = {new SqlParameter("date1", Types.DATE),new SqlParameter("date2", Types.DATE)};
itemReader.setParameters(parameter);
itemReader.setPreparedStatementSetter(psSetter);
 

где значения набора psSetter я определил следующим образом:

 ps.setDate(1, Date.ValueOf(paramList.get(0));
ps.setDate(2, Date.ValueOf(paramList.get(1));
 

Я также попробовал несколько других хранимых процедур и получил аналогичные проблемы.
Является ли это ошибкой с определением. Я просто хочу определить параметры предпочтительно по индексу. Есть ли какой-нибудь простой способ сделать это? Ожидает ли он, что параметры в storedproc будут конкретно названы date1/date2, и из-за этого произойдет сбой?

Ответ №1:

Для хранимых процедур вам нужно использовать StoredProcedureItemReader и не JdbcCursorItemReader использовать, что-то вроде:

 @Bean
public StoredProcedureItemReader storedProcedureItemReader() {
    StoredProcedureItemReader reader = new StoredProcedureItemReader();
    reader.setProcedureName("yourProcedureName");
    // set other properties
    return reader;
}
 

Пожалуйста, обратитесь к справочной документации для получения более подробной информации.

Комментарии:

1. Привет @Махмуд. Изменил его на StoredProcedureItemReader, но все еще сталкивался с аналогичными ошибками. Добавили все детали в вопрос. Не могли бы вы любезно дать мне знать, если я что-то здесь упущу.

2. Необходимы ли как setParameters, так и setPreparedStatementSetter? и как они должны быть связаны друг с другом?

3. Even after using StoredProcedureItemReader as suggested, getting the following error: For the declaration of this cursor to be legal it should have a single SELECT statement without a COMPUTE clause. Эта ошибка, по-видимому, связана с тем, что ваша хранимая процедура отклоняется Sybase и не связана с параметрами. Я не уверен, что весенняя партия может помочь на этом уровне.

4. Спасибо @Mahmoud. Будем расследовать это дальше. Просто для подтверждения: необходимы ли оба параметра setParameters и setPreparedStatementSetter? Как мы можем передать индексированные параметры в StoredProcedureItemReader??

5. Согласно afterPropertiesSet , ни один из них не является необходимым, обязательными свойствами являются только имена процедур и RowMapper.