首页 > 解决方案 > 不能用Hibernate调用PostgreSQL的11个存储过程

问题描述

PostgreSQL 11 现在支持存储过程,我正在尝试使用Hibernate 5.3.7.FinalPostgresql 42.2.5 JDBC driver调用一个。在 PostgreSQL 11 之前,我们有可以用 JPA 调用的函数@NamedStoredProcedure。但是,函数是用执行的SELECT my_func();,新的存储过程必须用CALL my_procedure();

我正在尝试执行以下简单的存储过程:

CREATE OR REPLACE PROCEDURE p_raise_wage_employee_older_than(operating_years 
int, raise int)
AS $$
    BEGIN
       UPDATE employees
       SET wage = wage + raise 
       WHERE EXTRACT(year FROM age(entrance_date)) >= operating_years;
    END $$
LANGUAGE plpgsql;

JPA 注释如下所示:

@NamedStoredProcedureQuery(name = "raiseWage", 
   procedureName = "p_raise_wage_employee_older_than", 
   parameters = {
        @StoredProcedureParameter(name = "operating_years", type = Integer.class, 
           mode = ParameterMode.IN),
        @StoredProcedureParameter(name = "raise", type = Integer.class, 
            mode = ParameterMode.IN)
})

我正在调用存储过程:

StoredProcedureQuery storedProcedureQuery = this.em.createNamedStoredProcedureQuery("raiseWage"); 
storedProcedureQuery.setParameter("operating_years", 20);
storedProcedureQuery.setParameter("raise", 1000);
storedProcedureQuery.execute();

我的日志如下所示:

Hibernate: {call p_raise_wage_employee_older_than(?,?)}
2019-02-17 11:07:41.290  WARN 11168 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 0, SQLState: 42809
2019-02-17 11:07:41.291 ERROR 11168 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: p_raise_wage_employee_older_than(integer, integer) is a procedure
  Hinweis: To call a procedure, use CALL.
  Position: 15

第一个 Hibernate 日志表明 Hibernate 用于call执行存储过程,但我得到一个CALL未使用的 SQL 异常。这是 Postgresql 11 之前的 Postgresql 方言中的错误,您能够FUNCTIONS在 JPA 中将存储过程建模为存储过程,因此SELECT被使用而不是CALL

标签: javapostgresqlhibernatejpaspring-data

解决方案


在 PostgreSQL 11 之后,PostgreSQL JDBC 驱动团队EscapeSyntaxCallMode在 PostgreSQL 驱动版本 42.2.16 中引入了一个 ENUM 名称。所以我们可以在创建数据库连接或创建 DataSource 对象时使用这个枚举。这个枚举有 3 种类型的值:

  1. " func" - 当我们总是想调用函数时设置它。
  2. " call" - 当我们总是想调用程序时设置它。
  3. " callIfNoReturn" - 它检查调用函数/过程中的返回类型,如果返回类型存在 PostgreSQL 将其视为函数并将其作为函数方式调用。否则将其称为过程方式。所以在我的项目中我使用了这个“ callIfNoReturn”,因为我希望 PostgreSQL 自动检测我是在调用函数还是过程。

我已经用正确的步骤详细给出了答案:

Postgresql 11:存储过程调用错误 - 要调用过程,请使用 CALL、Java


推荐阅读