PostgreSQL 11现在支持存储过程,我正在尝试使用 Hibernate 5.3.7.Final 和 Postgresql 42.2.5 JDBC驱动程序 进行调用。在PostgreSQL 11之前,我们有可以用JPA调用的函数@NamedStoredProcedure。但是,函数是通过执行的,SELECT my_func();而新的存储过程必须以CALL my_procedure();
@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中对as存储过程进行建模,因此可以SELECT使用它而不是CALL?
call
CALL
FUNCTIONS
SELECT
由于pgJDBC 42.2.5在PostgreSQL 11发行版(2018年10月)之前发布(2018年8月),我认为这目前是PostgreSQL本身的JDBC驱动程序中的问题。我在GitHub存储库中创建了一个问题。
要解决此问题,您可以将STORED PROCEDUREa 重写为a FUNCTION并使用@NamedStoredProcedureQuery或直接与JDBC交互,CallableStatement例如:
STORED PROCEDURE
FUNCTION
@NamedStoredProcedureQuery
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:
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