Hibernate:如何调用返回varchar的存储函数?
我试图使用Hibernate从Java调用Oracle9i数据库中的遗留存储函数。 该函数声明如下:
create or replace FUNCTION Transferlocation_Fix (mnemonic_code IN VARCHAR2) RETURN VARCHAR2
经过几次失败的尝试和广泛的谷歌搜索后,我在Hibernate论坛上发现了这个线程 ,它提出了这样的映射:
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语法exception……所以我尝试了Pascal建议的JDBC方式,它似乎工作了! 我在下面的答案中添加了代码。
我不是100%肯定,我没有测试它,但根据Hibernate的文档:
16.2.2。 使用存储过程进行查询
Hibernate3通过存储过程和函数为查询提供支持。 以下大多数文档都是等效的。 存储过程/函数必须返回一个结果集作为第一个能够使用Hibernate的out参数 。 Oracle 9及更高版本中此类存储函数的示例如下:
CREATE OR REPLACE FUNCTION selectAllEmployments RETURN SYS_REFCURSOR AS st_cursor SYS_REFCURSOR; BEGIN OPEN st_cursor FOR SELECT EMPLOYEE, EMPLOYER, STARTDATE, ENDDATE, REGIONCODE, EID, VALUE, CURRENCY FROM EMPLOYMENT; RETURN st_cursor; END;
要在Hibernate中使用此查询,您需要通过命名查询映射它。
{ ? = call selectAllEmployments() } 存储过程目前仅返回标量和实体。 不支持
和
。
16.2.2.1。 使用存储过程的规则/限制
除非遵循某些过程/函数规则,否则不能将存储过程与Hibernate一起使用。 如果他们不遵守这些规则,他们就无法使用Hibernate。 如果您仍想使用这些过程,则必须通过
session.connection()
执行它们 。 每个数据库的规则都不同,因为数据库供应商具有不同的存储过程语义/语法。无法使用
setFirstResult()/setMaxResults()
分页存储过程查询。推荐的呼叫表格是标准的SQL92:
{ ? = call functionName(
) } { ? = call functionName(
或) } { ? = call procedureName(
} { ? = call procedureName(
。不支持本机调用语法。} 对于Oracle,以下规则适用:
- 函数必须返回结果集。 过程的第一个参数必须是返回结果集的OUT。 这是通过在Oracle 9或10中使用SYS_REFCURSOR类型来完成的。在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 ...()}
{? = call ...()}
语法。 Oracle的select ... from dual
syntax是一个普通的查询,所以你不需要callable = true
:
select Transferlocation_Fix(:mnemonic) as retVal from dual
我遇到了类似的问题/问题,我已经意识到应该在sql部分进行更改,因为hibernate只能使用游标返回。 我在这里描述了一切: http : //www.len.ro/2011/10/call-oracle-procedure-from-hibernate/
- Hibernate HQL Join Query DOT节点没有左侧
- 通过Spring将字段注入由Hibernate加载的实体
- Send String second Argument IdentifierGenerator – Hibernate
- UTF – 8与JPA和Glassfish 4.0
- 遇到了一个已弃用的javax.persistence.spi.PersistenceProvider
- Hibernate> CLOB> Oracle :(
- JPA插入父/子会导致MySQLIntegrityConstraintViolationException
- Hibernate事务未成功启动
- Hibernatevalidation注释 – validation至少一个字段不为空