当前位置: 首页 > 面试题库 >

休眠:如何调用返回varchar的存储的函数?

羊渝
2023-03-14
问题内容

我试图使用Hibernate从Java调用Oracle9i DB中的遗留存储函数。该函数的声明如下:

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

经过几次失败的尝试和广泛的谷歌搜索之后,我在Hibernate论坛上发现了该线程,该线程建议了如下映射:

<sql-query name="TransferLocationFix" callable="true">
    <return-scalar column="retVal" type="string"/>
    select Transferlocation_Fix(:mnemonic) as retVal from dual
</sql-query>

我执行它的代码

    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

该函数确实进行了大量的插入/更新,因此我想运行它的唯一方法是使用存储过程语法。我只是不知道如何映射返回值:

<sql-query name="TransferLocationFix" callable="true">
    <return-scalar column="???" type="string"/>
    { ? = call Transferlocation_Fix(:mnemonic) }
</sql-query>

应该是什么column?我会尝试一个空值…

Update2: 同样失败,并带有SQL语法异常…因此,我尝试了Pascal建议的JDBC方式,它似乎可以工作!我在下面的答案中添加了代码。


问题答案:

我不确定100%,也没有测试,但是根据Hibernate的文档:

16.2.2。使用存储过程进行查询

Hibernate3通过存储过程和函数提供查询支持。以下大多数文档对于两者都是等效的。
存储过程/函数必须返回结果集作为第一个输出参数,才能与Hibernate一起使用 。在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中使用此查询,您需要通过命名查询将其映射。

<sql-query name="selectAllEmployees_SP" callable="true">
    <return alias="emp" class="Employment">
        <return-property name="employee" column="EMPLOYEE"/>
        <return-property name="employer" column="EMPLOYER"/>
        <return-property name="startDate" column="STARTDATE"/>
        <return-property name="endDate" column="ENDDATE"/>
        <return-property name="regionCode" column="REGIONCODE"/>
        <return-property name="id" column="EID"/>
        <return-property name="salary">
            <return-column name="VALUE"/>
            <return-column name="CURRENCY"/>
        </return-property>
    </return>
    { ? = call selectAllEmployments() }
</sql-query>

当前,存储过程仅返回标量和实体。 <return-join>并且 <load-collection>不受支持。

16.2.2.1。使用存储过程的规则/限制

除非遵循某些过程/功能规则,否则您不能在Hibernate中使用存储过程。 如果他们不遵守这些规则,则无法在Hibernate中使用。
如果仍然要使用这些过程,则必须通过来执行它们
session.connection()

。每个数据库的规则都不同,因为数据库供应商具有不同的存储过程语义/语法。

存储过程查询不能使用进行分页 setFirstResult()/setMaxResults()

推荐的调用形式为标准SQL92:{ ? = call functionName(<parameters>) }{ ? = call procedureName(<parameters>}。不支持本机调用语法。

对于Oracle,适用以下规则:

  • 函数必须返回结果集。 过程的第一个参数必须是返回结果集的OUT。这是通过在Oracle
    9或10中使用SYS_REFCURSOR类型完成的。
    在Oracle中,您需要定义REF CURSOR类型。有关更多信息,请参见Oracle文献。

如我所说,我不确定,但我的理解是您必须session.getConnection()在这里使用。



 类似资料:
  • 问题内容: 我正在尝试在hibernate状态下使用mysql 字符串函数,但不幸的是我无法使用它,甚至无法通过创建这些注册函数来尝试 使用mysqldialect但没有人在工作..任何人都可以告诉我如何在hibernate状态下使用mysql字符串函数。或对上述寄存器功能的任何更改。 提前致谢, 最好的问候,拉贾。 问题答案: 通过扩展mysqldialect来创建一个类,如下所示 } 并在查询

  • 问题内容: 我在使用hibernate和MySQL时遇到了一些问题。我一直在读书,但我变得更加困惑,所以我想你可以帮助我理解下一步该怎么做。 我有一个MySQL数据库,在其中添加了此存储过程(感谢Stack Overflow的人们) 我读过某个地方,使用hibernate模式调用函数和过程将非常相似。然后,我发现(巧合地也在StackOverflow中)使用Hibernate从我的Java应用程序

  • 问题内容: 我无法理解使用Hibernate Callback方法的优势,是否有任何优势或应使用的特定用例。 还有一个更重要的问题是HibernateCallback方法是否在查询返回值后每次都关闭会话?我有用例,每次刷新状态页时都会多次调用此函数,因此每次打开会话和查询数据库时都会调用此函数,或者将查询结果存储在内存中,然后每次调用此函数时,都会弹出结果从记忆里。 我已阅读(参考): 春天的Hi

  • 问题内容: 我已经在 MySQL存储过程 e中编写了一些逻辑。我正在将 spring boot与hibernate一起使用 。我有一个使用 IN OUT 参数的登录过程。从我的登录过程中,我想将消息传递给用户。但是我不知道如何在Spring Boot中调用存储过程。我的代码在下面。 我的登录过程是 我用过像 在我的登录控制器中,我想调用我的过程,以便可以将我的用户转发到仪表板。如果用户输入了错误的

  • 我找到了一些很好的SO链接(如何从异步回调函数返回值?以及从node.js中的回调函数返回值等),但它们并不是不能为我的问题提供解决方案。 我的问题:能够得到异步调用的结果,但我如何使用这个结果返回我的函数? 这里获取callBackResponse的值为true或false,并希望将该值用作:

  • 相对来说,我是一个与Java智能合约交互的新手,在尝试检索智能合约函数返回的tuple[]时遇到了一个问题。这是我想调用的函数的ABI定义: 以下是智能合约代码的链接:https://polygonscan . com/address/0x 920 f 22 E1 e 5 da 04504 b 765 f 8110 ab 96 a 20 e 6408 BD # code 下面是我编写的调用该函数的