为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

慕姐4208626 2022-06-23 17:02:01
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: 428092019-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?
查看完整描述

2 回答

?
小怪兽爱吃肉

TA贡献1852条经验 获得超1个赞

由于 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


查看完整回答
反对 回复 2022-06-23
?
慕工程0101907

TA贡献1887条经验 获得超5个赞

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

  1. func" - 当我们总是想调用函数时设置它。

  2. call" - 当我们总是想调用程序时设置它。

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


查看完整回答
反对 回复 2022-06-23
  • 2 回答
  • 0 关注
  • 276 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信