我可以使用 postgres JDBC 驱动程序从 java 调用 postgres“程序”(不是“函数”)吗?

mis*_*oof 2 stored-procedures jdbc spring-jdbc postgresql-11

我是 postgres 的新手,但我试图在 Postgres 11 中调用一个过程(新的“过程”而不是“函数”),从 java 作为 spring SimpleJDBCCall 调用(使用 Postgresql-42.2.5 jdbc 驱动程序)。但是,当我执行该过程时,遇到以下异常:

org.springframework.jdbc.BadSqlGrammarException: CallableStatementCallback; 错误的 SQL 语法 [{call pa_test_schema.pr_dosomething(?)}]; 嵌套异常是 org.postgresql.util.PSQLException:错误:pa_test_schema.pr_dosomething(bigint) 是一个过程提示:要调用一个过程,请使用 CALL。位置:15 在 org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:101) 在 org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72) 在 org.springframework.jdbc AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) 在 org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:

我的程序代码:

CREATE PROCEDURE pa_test_schema.pr_DoSomething
( P_input_ID IN inputs.input_ID%TYPE
) AS $$
BEGIN
    -- do something   
END; 
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

我的Java代码:

SimpleJdbcCallOperations pr_DoSomething =  new SimpleJdbcCall(jdbcTemplate)
        .withSchemaName("pa_test_schema")
        .withProcedureName("pr_DoSomething");
Map<String, Object> inputs = Maps.newHashMap();
inputs.put("p_input_id", 123456);

pr_DoSomething.execute(inputs);    
Run Code Online (Sandbox Code Playgroud)

当我逐步执行代码时,我可以看到驱动程序正在将可调用语句的 sql 修改为调用 postgres 函数所需的语法:

select * from pa_test_schema.pr_dosomething(?) 作为结果

这是执行此转换的驱动程序中的方法:https : //github.com/pgjdbc/pgjdbc/blob/faab499853c56f67cb70fb242f75b918452f2a6f/pgjdbc/src/main/java/org/postgresql/core/Parser6.java

我了解过程仅在 Postgres 11 中引入(以前会使用返回 void 的函数),并且已经通读了 postgres 驱动程序文档,但没有看到任何对调用过程而不是函数的引用。

这是否意味着当前的 postgres 驱动程序尚不支持此功能,还是我应该使用另一种方法?我应该只使用 postgres 函数吗?

a_h*_*ame 7

当前(从 Postgres 11.1 和驱动程序版本 42.2.5 开始)使用 a 的标准 JDBC 方法CallableStatement不能用于调用存储过程。

我并没有真正使用 Spring JDBC 模板,但以下代码在普通 JDBC 中工作并且应该适用于 Spring JDBC Tempalte:

Connection con = DriverManager.getConnection(...);
PreparedStatement pstmt = con.prepareStatement("call pa_test_schema.pr_DoSomething(?)");
pstmt.setInt(1, 42);
pstmt.execute();
Run Code Online (Sandbox Code Playgroud)

请注意,这使用了 Postgres 的call命令。不要将此与 a 的"{call ...}"语法混淆CallableStatement


可以在此处此处的 JDBC 邮件列表中找到有关当前 CallableStatement 为何不起作用的更多详细信息