Я пытаюсь вызвать сохраненную функцию наследия в 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, как предложено Паскалем, и это, кажется, работает! Я добавил код в ответе ниже.
Я не уверен на 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()
.
Для справки, вот мое окончательное решение:
CallableStatement statement = session.connection().prepareCall(
"{ ? = call Transferlocation_Fix(?) }");
statement.registerOutParameter(1, Types.VARCHAR);
statement.setString(2, "FC3");
statement.execute();
String result = statement.getString(1);
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>