【问题标题】:JPA 2.1 StoredProcedureQuery with PostgreSQL and REF_CURSORs带有 PostgreSQL 和 REF_CURSOR 的 JPA 2.1 StoredProcedureQuery
【发布时间】:2016-02-11 18:51:38
【问题描述】:

我有一个在我的 PostgreSQL 数据库中创建的函数,我想使用 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

这只是一个简单的查询,用于计算特定日期的用户数。这只是一个演示查询,用于测试 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();

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

org.hibernate.HibernateException: PostgreSQL supports only one REF_CURSOR parameter, but multiple were registered

只声明了一个引用游标!事实上,如果我只是在我的 Postgresql 函数的 WHERE date_ = date 的值中注册单个 REF_CURSOR 参数和硬编码,那么这个调用就可以正常工作。

因此,使用 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

在爪哇岛:

StoredProcedureQuery storedProcedure =    em.createStoredProcedureQuery("get_values");
storedProcedure.registerStoredProcedureParameter(1, Object.class, ParameterMode.REF_CURSOR);
storedProcedure.execute();

【问题讨论】:

    标签: java hibernate postgresql jpa


    【解决方案1】:

    简答:将两次调用的顺序颠倒到registerStoredProcedureParameter()

    storedProcedure.registerStoredProcedureParameter(1, Object.class, ParameterMode.REF_CURSOR);
    storedProcedure.registerStoredProcedureParameter(2, String.class, ParameterMode.IN);
    

    长答案:我在Hibernate source code for Postgress callable statement support 中进行了一些挖掘,发现每个registerStoredProcedureParameter() 调用都会创建一个ParameterRegistrationImplementor 实例,该实例被添加到列表中并被传递。你会注意到这个类存储了参数的位置,它独立于它在列表中的位置。

    稍后,此列表为 analyzed,并假定 REF_CURSOR 参数将排在第一个,如果 REF_CURSOR 参数不是第一个,则抛出错误消息,无论参数号是什么.

    这不是一种非常聪明的做事方式(恕我直言),但至少解决方法很简单:如果您交换调用顺序,应该没问题。

    【讨论】:

    • 让我试试这个然后回复你!
    猜你喜欢
    • 1970-01-01
    • 2014-07-07
    • 1970-01-01
    • 2011-07-09
    • 2014-11-02
    • 2011-08-27
    • 2021-01-24
    • 2017-09-15
    • 2011-01-05
    相关资源
    最近更新 更多