无法使用 Hibernate 调用 PostgreSQL 的 11 个存储过程

rie*_*pil 7 java postgresql hibernate jpa spring-data

PostgreSQL 11 现在支持存储过程,我正在尝试使用Hibernate 5.3.7.FinalPostgresql 42.2.5 JDBC 驱动程序调用一个。在 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;
Run Code Online (Sandbox Code Playgroud)

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)
})
Run Code Online (Sandbox Code Playgroud)

我正在调用存储过程:

StoredProcedureQuery storedProcedureQuery = this.em.createNamedStoredProcedureQuery("raiseWage"); 
storedProcedureQuery.setParameter("operating_years", 20);
storedProcedureQuery.setParameter("raise", 1000);
storedProcedureQuery.execute();
Run Code Online (Sandbox Code Playgroud)

我的日志如下所示:

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
Run Code Online (Sandbox Code Playgroud)

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

rie*_*pil 3

由于 pgJDBC 42.2.5 是在 PostgreSQL 11 版本(2018 年 10 月)之前发布的(2018 年 8 月),我认为这是目前 PostgreSQL 本身的 JDBC 驱动程序中的一个问题。我创建了一个问题在 GitHub 存储库中

对于解决方法,您可以将其重写STORED PROCEDURE为 aFUNCTION并使用@NamedStoredProcedureQuery或直接与 JDBC 交互,CallableStatement例如:

Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/", "postgres", "postgres");

CallableStatement callableStatement = conn.prepareCall("{call f_raise_wage_employee_older_than(?,?)}");
callableStatement.setInt(1, 20);
callableStatement.setInt(2, 500);
callableStatement.executeUpdate();
Run Code Online (Sandbox Code Playgroud)

或者使用以下命令执行本机查询EntityManager

this.em.createNativeQuery("CALL p_raise_wage_employee_older_than(1, 20)");
Run Code Online (Sandbox Code Playgroud)

一旦我从 pgJDBC 维护者那里得到答案,我就会更新这个答案。

更新:

这个主题已经在 Postgres 邮件列表 ( https://www.postgresql.org/message-id/4285.1537201440%40sss.pgh.pa.us ) 中讨论过,目前没有解决方案。唯一的方法是将本机 SQL 查询传递到数据库或将其重写STORED PROCEDUREFUNCTION