使用PostgreSQL和REF_CURSORs的JPA 2.1 StoredProcedureQuery

ros*_*hal 4 java postgresql hibernate jpa

我有一个我在PostgreSQL DB中创建的函数,我想用JPA 2.1的StoredProcedureQuery方法调用它.

这是我的PostgreSQL查询:

CREATE OR REPLACE FUNCTION get_values(date text) returns refcursor 
AS $$ 
    DECLARE tuples refcursor; 
    BEGIN OPEN tuples FOR 
        SELECT user, COUNT(*) 
        FROM my_table 
        WHERE date_ = date
        GROUP BY user; 
    return tuples; 
    END; 
$$ 
LANGUAGE plpgsql
Run Code Online (Sandbox Code Playgroud)

这只是在特定日期对用户进行计数的简单查询.这只是一个演示查询,用于测试StoredProcedureQueries的工作方式.事实上,仅通过postgreSQL使用它就可以了.

现在,让我们尝试使用JPA 2.1和Javaland调用它:

StoredProcedureQuery storedProcedure = em.createStoredProcedureQuery("get_values");
storedProcedure.registerStoredProcedureParameter(2, String.class, ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter(1, Object.class, ParameterMode.REF_CURSOR);
storedProcedure.setParameter(2, "2015-02-01");
storedProcedure.execute();
Run Code Online (Sandbox Code Playgroud)

当我这样做时,我得到以下异常:

org.hibernate.HibernateException: PostgreSQL supports only one REF_CURSOR parameter, but multiple were registered
Run Code Online (Sandbox Code Playgroud)

声明只有一个引用游标!实际上,如果我只是为WHERE date_ = date注册了单个REF_CURSOR参数和硬编码我的Postgresql函数的值,那么这个调用就可以了.

因此,似乎使用ref_cursor向存储过程查询添加任何其他参数会破坏功能.单独,ref_cursor参数工作正常.

谁知道为什么会这样?为什么在PostgreSQL函数的StoredProcedureQuery中添加参数会破坏它?

它何时起作用的示例:

 CREATE OR REPLACE FUNCTION get_values(date text) returns refcursor 
AS $$ 
    DECLARE tuples refcursor; 
    BEGIN OPEN tuples FOR 
        SELECT user, COUNT(*) 
        FROM my_table 
        WHERE date_ = '2015-02-01'
        GROUP BY user; 
    return tuples; 
    END; 
$$ 
LANGUAGE plpgsql
Run Code Online (Sandbox Code Playgroud)

在javaland:

StoredProcedureQuery storedProcedure =    em.createStoredProcedureQuery("get_values");
storedProcedure.registerStoredProcedureParameter(1, Object.class, ParameterMode.REF_CURSOR);
storedProcedure.execute();
Run Code Online (Sandbox Code Playgroud)

dcs*_*ohl 5

简答:将您的两个电话的顺序颠倒过来registerStoredProcedureParameter():

storedProcedure.registerStoredProcedureParameter(1, Object.class, ParameterMode.REF_CURSOR);
storedProcedure.registerStoredProcedureParameter(2, String.class, ParameterMode.IN);
Run Code Online (Sandbox Code Playgroud)

答案很长:我在Postgress可调用语句支持Hibernate源代码中做了一些挖掘,发现每次registerStoredProcedureParameter()调用都会创建一个ParameterRegistrationImplementor被添加到列表中并传递的实例.您将注意到此类存储参数的位置,该位置与其在列表中的位置无关.

稍后,将对此列表进行分析,并假定该REF_CURSOR参数将排在第一位,并且如果REF_CURSOR参数不是第一个,则抛出错误消息,无论参数编号是什么.

不是一个非常聪明的做事方式(恕我直言),但至少解决方法很简单:如果你改变你的电话顺序,你应该没事.