有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我有一个返回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)

我该如何解决这个问题

甲骨文功能

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")

和在道中

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

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

共 (2) 个答案

  1. # 1 楼答案

    为了你的功能

    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;
    

    您可以定义以下NamedNativeQuery

    @NamedNativeQuery(
        name = "my_function",
        query = "{ ? = call my_function( ? ) }",
        callable = true,
        resultClass = String.class
    )
    

    您可以这样调用查询:

    List<String> employeeNames = entityManager
        .createNamedQuery("my_function")
        .setParameter(1, 1L)
        .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;
    

    ,您可以使用以下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();
    
  2. # 2 楼答案

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

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

    有关函数的定义,请参见http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions231.htm#i1012049

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