Будьте в спящем режиме: как вызвать сохраненную функцию, возвратив varchar?

Я пытаюсь вызвать сохраненную функцию наследия в Oracle9i DB от использования Java, в спящем режиме. Функция объявляется как это:

create or replace FUNCTION Transferlocation_Fix (mnemonic_code IN VARCHAR2)
   RETURN VARCHAR2

После нескольких неудавшихся попыток и обширного поиска с помощью Google, я нашел этот поток на Быть в спящем режиме форумах, которые предложили отображение как это:


    
    select Transferlocation_Fix(:mnemonic) as retVal from dual

Мой код для выполнения его

    Query query = session.getNamedQuery("TransferLocationFix");
    query.setParameter("mnemonic", "FC3");
    String result = (String) query.uniqueResult();

и получающийся журнал

DEBUG (org.hibernate.jdbc.AbstractBatcher:366) -  - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG (org.hibernate.SQL:401) -  - select Transferlocation_Fix(?) as retVal from dual
TRACE (org.hibernate.jdbc.AbstractBatcher:484) -  - preparing statement
TRACE (org.hibernate.type.StringType:133) -  - binding 'FC3' to parameter: 2
TRACE (org.hibernate.type.StringType:133) -  - binding 'FC3' to parameter: 2

java.lang.NullPointerException
at oracle.jdbc.ttc7.TTCAdapter.newTTCType(TTCAdapter.java:300)
at oracle.jdbc.ttc7.TTCAdapter.createNonPlsqlTTCColumnArray(TTCAdapter.java:270)
at oracle.jdbc.ttc7.TTCAdapter.createNonPlsqlTTCDataSet(TTCAdapter.java:231)
at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1924)
at oracle.jdbc.ttc7.TTC7Protocol.parseExecuteDescribe(TTC7Protocol.java:850)
at oracle.jdbc.driver.OracleStatement.doExecuteQuery(OracleStatement.java:2599)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:2963)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:658)
at oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.java:736)
at com.mchange.v2.c3p0.impl.NewProxyCallableStatement.execute(NewProxyCallableStatement.java:3044)
at org.hibernate.dialect.Oracle8iDialect.getResultSet(Oracle8iDialect.java:379)
at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:193)
at org.hibernate.loader.Loader.getResultSet(Loader.java:1784)
at org.hibernate.loader.Loader.doQuery(Loader.java:674)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
at org.hibernate.loader.Loader.doList(Loader.java:2220)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2104)
at org.hibernate.loader.Loader.list(Loader.java:2099)
at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:289)
at org.hibernate.impl.SessionImpl.listCustomQuery(SessionImpl.java:1695)
at org.hibernate.impl.AbstractSessionImpl.list(AbstractSessionImpl.java:142)
at org.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:152)
at org.hibernate.impl.AbstractQueryImpl.uniqueResult(AbstractQueryImpl.java:811)
at com.my.project.SomeClass.method(SomeClass.java:202)
...

Какие-либо подсказки, что я делаю неправильно? Или какие-либо лучшие способы вызвать эту сохраненную функцию?


Обновление: после попытки предложения @axtavt я получаю следующую ошибку:

ORA-14551: cannot perform a DML operation inside a query

Функция действительно делает обширный, вставляет/обновляет, таким образом, я предполагаю единственный способ работать, это использовало бы синтаксис хранимой процедуры. У меня просто нет подсказки, как отобразить возвращаемое значение:


    
    { ? = call Transferlocation_Fix(:mnemonic) }

Что должно быть column? Я попробую пустое значение...


Update2: это перестало работать также за Исключением Грамматики SQL... Таким образом, я попробовал путь JDBC, как предложено Паскалем, и это, кажется, работает! Я добавил код в ответе ниже.

5
задан Péter Török 1 June 2010 в 12:43
поделиться

3 ответа

Я не уверен на 100% и не проверял это, но согласно документации Hibernate:

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

Hibernate3 обеспечивает поддержку запросов с помощью хранимых процедур и функции. Большая часть документация эквивалентна для обеих. Хранимая процедура/функция должна возвращать набор результатов в качестве первого выводимый параметр, чтобы иметь возможность работать с Hibernate. Пример такой хранимой функции в Oracle 9 и выше выглядит следующим образом:

CREATE OR REPLACE FUNCTION selectAllEmployments
 RETURN SYS_REFCURSOR
AS
 st_cursor SYS_REFCURSOR;
BEGIN
 ОТКРЫТЬ st_cursor ДЛЯ
 SELECT EMPLOYEE, EMPLOYER,
 ДАТА НАЧАЛА, ДАТА ОКОНЧАНИЯ,
 REGIONCODE, EID, VALUE, CURRENCY
 ИЗ ТРУДОУСТРОЙСТВА;
 RETURN st_cursor;
 END;

Чтобы использовать этот запрос в Hibernate, необходимо необходимо отобразить его через именованный запрос.


 
 
 
 
 
 
 
 
 
 
 
 
 { ? = call selectAllEmployments() }

Хранимые процедуры в настоящее время возвращают скаляры и сущности. and не поддерживаются.

16.2.2.1. Правила/ограничения для использования хранимых процедур

Вы не можете использовать хранимые процедуры в Hibernate, если вы не следуете некоторым правила использования процедур/функций. Если они не следуют этим правилам, они не могут быть использованы в Hibernate. Если вы все же хотите использовать эти процедуры, вы должны выполнить их через session.connection(). Правила разные для каждой базы данных, поскольку поставщики баз данных имеют различные семантика/синтаксис хранимых процедур.

Запросы хранимых процедур не могут быть вызывать с помощью setFirstResult()/setMaxResults().

Рекомендуемая форма вызова является стандартной SQL92: { ? = call functionName(<параметры>) } или { ? = call procedureName(<параметры>}. Нативный синтаксис вызова не поддерживается.

Для Oracle действуют следующие правила:

  • Функция должна возвращать набор результатов. Первый параметр процедуры должен быть OUT, который возвращает набор результатов. Это делается с помощью SYS_REFCURSOR в Oracle 9 или 10. В Oracle необходимо определить тип REF CURSOR. См. литературу по Oracle для получения дополнительной информации.

...

Как я уже сказал, я не уверен, но, насколько я понимаю, здесь вам придется использовать session.getConnection().

2
ответ дан 18 December 2019 в 10:42
поделиться

Для справки, вот мое окончательное решение:

CallableStatement statement = session.connection().prepareCall(
        "{ ? = call Transferlocation_Fix(?) }");
statement.registerOutParameter(1, Types.VARCHAR);
statement.setString(2, "FC3");
statement.execute();
String result = statement.getString(1);
10
ответ дан 18 December 2019 в 10:42
поделиться

callable = true предназначен для вызова хранимых процедур с синтаксисом {? = call ...()}. Синтаксис Oracle select ... from dual - это обычный запрос, поэтому вам не нужен callable = true:

<sql-query name="TransferLocationFix"> 
    <return-scalar column="retVal" type="string"/> 
    select Transferlocation_Fix(:mnemonic) as retVal from dual 
</sql-query> 
2
ответ дан 18 December 2019 в 10:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: