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