不能用Hibernate调用PostgreSQL的11个存储过程

PostgreSQL 11 现在支持存储过程,我正在尝试使用Hibernate 5.3.7.Final和Postgresql 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?


慕姐4208626
浏览 277回答 2
2回答

小怪兽爱吃肉

由于 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();或使用以下命令执行本机查询EntityManager:this.em.createNativeQuery("CALL p_raise_wage_employee_older_than(1, 20)");一旦我从 pgJDBC 维护者那里得到答案,我就会更新这个答案。更新:这个话题已经在 Postgres 邮件列表(https://www.postgresql.org/message-id/4285.1537201440%40sss.pgh.pa.us)中讨论过,目前没有解决方案。唯一的方法是将本地 SQL 查询传递给数据库或重写STORED PROCEDURE为FUNCTION

慕工程0101907

在 PostgreSQL 11 之后,PostgreSQL JDBC 驱动团队EscapeSyntaxCallMode在 PostgreSQL 驱动版本 42.2.16 中引入了一个 ENUM 名称。所以我们可以在创建数据库连接或创建 DataSource 对象时使用这个枚举。这个枚举有 3 种类型的值:" func" - 当我们总是想调用函数时设置它。" call" - 当我们总是想调用程序时设置它。" callIfNoReturn" - 它检查调用函数/过程中的返回类型,如果返回类型存在 PostgreSQL 将其视为函数并将其作为函数方式调用。否则将其称为过程方式。所以在我的项目中我使用了这个“ callIfNoReturn”,因为我希望 PostgreSQL 自动检测我是在调用函数还是过程。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java