Java 如何使用Hibernate(EntityManager)或JPA调用Oracle函数或过程

Java 如何使用Hibernate(EntityManager)或JPA调用Oracle函数或过程,java,oracle,hibernate,jpa,sys-refcursor,Java,Oracle,Hibernate,Jpa,Sys Refcursor,我有一个返回sys refcursor的Oracle函数,当我使用Hibernate调用这个函数时,我得到以下异常 Hibernate: { ? = call my_function(?) } org.hibernate.exception.GenericJDBCException: could not execute query javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCExcepti

我有一个返回sys refcursor的Oracle函数,当我使用Hibernate调用这个函数时,我得到以下异常

Hibernate: { ? = call my_function(?) }
 org.hibernate.exception.GenericJDBCException: could not execute query
javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not execute query
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1360)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1288)
    at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:313)
我如何解决这个问题

Oracle功能

create or replace 
FUNCTION my_function(p_val IN varchar2)
    RETURN SYS_REFCURSOR
  AS
    my_cursor SYS_REFCURSOR;
  BEGIN
    OPEN my_cursor FOR SELECT emp_name FROM employees
    WHERE lower(emp_name) like lower(p_val||'%');
    RETURN my_cursor;    
  END;
我的实体类

@Entity
@javax.persistence.NamedNativeQuery(name = "getFunc", query = 
"{ ? = call my_function(:empName) }", 
 resultClass = Employee.class, hints = 
 { @javax.persistence.QueryHint(name = "org.hibernate.callable", value = "true") })
 @Table(name = "EMPLOYEES")
和in-DAO

    @Override
        public void findEmployees(QueryData data,
                String empName) {

        List query = (List) entityManager.createNamedQuery("getFunc")
                         .setParameter("empName", empName)
                         .getSingleResult();
                data.setResult(query);
}

您似乎混淆了Oracle函数和Oracle存储过程

函数可以从select语句中调用—像您这样的用户定义函数与内置函数(如min()和max())的作用方式相同。它们不能像存储过程那样被外部“调用”调用

有关函数的定义,请参见


您可能需要将函数作为存储过程重新编写。

JPA 2.1早期草案指出,Oracle将支持存储过程

对存储过程的支持:添加了对Java持久性查询语言调用预定义数据库函数和用户定义数据库函数的支持

有不同的
EntityManager.CreateXXXStoredProcedureRequesty
方法变体,这些方法返回用于执行存储过程的StoredProcedureRequesty。就像
@NamedQuery
一样,有一个
@namedStoredProcedureRequesty
指定并命名存储过程、其参数和结果类型。可以在实体或映射超类上指定此注释。注释中指定的名称随后用于
EntityManager.CreateNamedStoredProcedureRequesty
。可以设置IN、OUT和INOUT参数,并用于检索从过程传回的值。例如:


至于规范何时会最终确定,或者Hibernate何时会支持JPA2.1,我不能说。但这可能值得注意。

可以通过以下方式使用EntityManager调用Oracle函数或存储过程

用于Oracle功能

create or replace 
FUNCTION my_function(p_val IN varchar2)
    RETURN SYS_REFCURSOR
  AS
    my_cursor SYS_REFCURSOR;
  BEGIN
    OPEN my_cursor FOR SELECT emp_name FROM employees
    WHERE lower(emp_name) like lower(p_val||'%');
    RETURN my_cursor;    
  END;
创建一个返回类型为sys\u refcursor的函数

CREATE OR REPLACE FUNCTION my_function
(p_val IN varchar2)
    RETURN SYS_REFCURSOR
  AS
    my_cursor SYS_REFCURSOR;
  BEGIN
    OPEN my_cursor FOR SELECT emp_name FROM employees
    WHERE lower(emp_name) like lower(p_val||'%');
    RETURN my_cursor;    
  END;
在实体类中,将函数定义为

@javax.persistence.NamedNativeQuery(name = "getFunc", query = "{? =  call
my_function(:empName) }", resultClass = Employee.class, hints = {
@javax.persistence.QueryHint(name = "org.hibernate.callable", value = "true") })
用于Oracle存储过程

使用
sys\u refcursor
作为先出参数创建过程

CREATE OR REPLACE PROCEDURE myProcedure(p_cursor out sys_refcursor,
     p_val  in varchar2
)
 AS
BEGIN
     OPEN o_cursor FOR
          SELECT     emp_name 
             FROM     employees 
            WHERE     LOWER (emp_name) LIKE lower(p_val||'%');
在实体类中,将过程定义为

@javax.persistence.NamedNativeQuery(name = "getProc", query = "{ call
my_procedure(?,:empName) }", resultClass = Employee.class, hints = {
@javax.persistence.QueryHint(name = "org.hibernate.callable", value = "true") })
Query query = entityManager.createNamedQuery("getFunc"); // if procedure then getProc 
query.setParameter("empName","smith"); 
query.getResultList(); 
最后在DAO类中调用函数或过程作为

@javax.persistence.NamedNativeQuery(name = "getProc", query = "{ call
my_procedure(?,:empName) }", resultClass = Employee.class, hints = {
@javax.persistence.QueryHint(name = "org.hibernate.callable", value = "true") })
Query query = entityManager.createNamedQuery("getFunc"); // if procedure then getProc 
query.setParameter("empName","smith"); 
query.getResultList(); 

谢谢

前面的解决方案似乎对eclipselink不起作用。我在JPA下运行了本机查询,并使用

            List result = em.createNativeQuery("select YOURFUNCTION(?) from dual ")
                      .setParameter(1, ONEPARAMETER)
                      .getResultList();
为了你的功能

create or replace 
FUNCTION my_function(p_val IN varchar2)
    RETURN SYS_REFCURSOR
  AS
    my_cursor SYS_REFCURSOR;
  BEGIN
    OPEN my_cursor FOR SELECT emp_name FROM employees
    WHERE lower(emp_name) like lower(p_val||'%');
    RETURN my_cursor;    
  END;
您可以定义以下
namedNativeRequesty

@NamedNativeQuery(
    name = "my_function",
    query = "{ ? = call my_function( ? ) }",
    callable = true,
    resultClass = String.class
)
您可以这样调用查询:

List<String> employeeNames = entityManager
    .createNamedQuery("my_function")
    .setParameter(1, 1L)
    .getResultList();
,您可以使用以下JPA 2.1查询:

StoredProcedureQuery query = entityManager
    .createStoredProcedureQuery("my_procedure")
    .registerStoredProcedureParameter(1, String.class, 
         ParameterMode.IN)
    .registerStoredProcedureParameter(2, Class.class, 
         ParameterMode.REF_CURSOR)
    .setParameter(1, 1L);
 
query.execute();
 
List<Object[]> result = query.getResultList();
StoredProcedureQuery=entityManager
.createStoredProcedureQuery(“我的程序”)
.registerStoredProcedureParameter(1,String.class,
ParameterMode.IN)
.registerStoredProcedureParameter(2,Class.Class,
参数模式参考(光标)
.设置参数(1,1L);
query.execute();
List result=query.getResultList();

程序:

CREATE OR REPLACE PROCEDURE my_procedure(p_val IN VARCHAR2, 
  my_cursor OUT SYS_REFCURSOR) 
AS
BEGIN
  OPEN my_cursor FOR SELECT emp_name FROM employees 
      WHERE lower(emp_name) like lower(p_val||'%');
END;
替代解决方案:使用sys\u refcursor作为OUT参数调用过程,而不定义@namednaviquery

StoredProcedureQuery query = entityManager.createStoredProcedureQuery("myProcedure");
    query.registerStoredProcedureParameter(1, void.class, ParameterMode.REF_CURSOR);
    query.registerStoredProcedureParameter(2, String.class, ParameterMode.IN);
    query.setParameter(2, "Umesh");
    List result = query.getResultList();

命名查询与存储过程不同。我不确定你能不能按你的建议去做。@duffymo那么使用Hibernate 4,调用数据库函数的最佳方式是什么呢?类似这样的:是的,你是对的,我可以使用select语句调用函数,比如
select my_function('smith')from dual
。使用Hibernate 4 EntityManager如何调用此函数或select语句以获得所需的结果?感谢基于您的功能,看起来您需要将其设置为存储过程而不是函数。正在调用pl/sql函数,但未使用EntityManager。这是怎么实现的?嗯,我发誓这是不可能的。我个人在这里没有答案。灰胡子怪我已经设法使用EntityManager(Hibernate 4)调用了Oracle函数或过程,请参阅我的答案。谢谢。有一个问题,我正在使用一个Oracle函数,所以我可以使用
@namedStoredProcedureRequesty
?这是规范所说的,但它可能在现在和最终版本之间发生变化(在编写Hibernate时,Hibernate还没有实现JPA 2.1,但似乎)。prunge我已经设法使用EntityManager调用了Oracle函数或过程(Hibernate 4),请参阅我的答案。无论如何,谢谢。JPA 2.1引入了对存储过程更好的支持(例如,多个输出参数)。有关更多详细信息,请参阅JPA 2.1引入了对存储过程更好的支持(例如,多个输出参数)。详情请参阅details@Jacob嘿,我在调用函数时遇到了无效的列索引异常。原因是什么?@FaizanMubasher我认为应该发布一个带有代码片段的问题以进行分析,而不是注释。你是对的!但是我有一个问题:是的,你可能是对的,它对EclipseLink不起作用。我试过了带Hibernate的帽子。如果您使用Eclipselink,请尝试使用多个参数(输入和输出)查找
使用JPQL和本机SQL查询JPA实体: