Swo*_*get 5 java postgresql procedure jdbc psql
我正在使用 Postgres 12 并编写了以下过程:
CREATE OR REPLACE PROCEDURE reduceStock(id INTEGER, soldQuantity INTEGER)
LANGUAGE plpgsql AS
$$
BEGIN
UPDATE inventory SET ProductStockAmount = ProductStockAmount - soldQuantity WHERE ProductID = id;
END;
$$;
Run Code Online (Sandbox Code Playgroud)
如果我在命令行上打开 psql 并运行,它会完美运行call reduceStock(1,1);
但是,从我的 Java 程序中调用它如下:
CallableStatement stmt = conn.prepareCall("{call reduceStock(?, ?)}");
stmt.setInt(1, productID);
stmt.setInt(2, quantity);
stmt.execute();
Run Code Online (Sandbox Code Playgroud)
call reduceStock(1,1);从 psql 客户端运行- 完美运行call任何想法,将不胜感激
小智 9
您需要删除花括号,它是调用过程的 JDBC 转义。但因为 Postgres 有它自己的call命令,所以不需要它们(并且与 JDBC 转义冲突)。
CallableStatement stmt = conn.prepareCall("call reducestock(?, ?)");
Run Code Online (Sandbox Code Playgroud)
过程 inocation ( {call reduceStock(?, ?)}) 周围的大括号意味着这不是本机 SQL,而是 JDBC 语法。您可以在此处阅读更多相关信息:Why do JDBC Calls to Stored procedure 将调用括在大括号中?。
因此,像这样的调用仍然必须由 JDBC 驱动程序转换为本机 SQL。默认情况下,Postgres 驱动程序将此类语句视为函数调用并将它们转换为SELECT reduceStock(?, ?)SQL 查询。这不是在 Postgres 中调用存储过程的方式。在Postgres中,存储过程调用SQL是call reduceStock(?, ?)。
使其发挥作用的一种方法是,就像@a_horse_with_no_name在他的回答中写的那样,删除花括号。这使得该语句成为本机调用,并且因为它是有效的 Postgres SQL,所以它会起作用。缺点是它的跨平台性较差,因为它不适用于不支持语法的数据库call procname()。例如,这不适用于 Oracle,因此如果您必须支持多个 JDBC 驱动程序,那么这是不太优选的方法。
更好的解决方法是提示 Postgres JDBC 驱动程序将此语法视为存储过程调用而不是函数调用,并将其相应地转换为 SQL。为此,Postgres 驱动程序公开了escapeSyntaxCallMode配置属性(另请查看EscapeSyntaxCallMode 枚举):
指定驱动程序如何将 JDBC 转义调用语法转换为基础 SQL,以调用过程或函数。(backend >= 11) 在 escapeSyntaxCallMode=select 模式(默认)下,驱动程序始终使用 SELECT 语句(仅允许函数调用)。在 escapeSyntaxCallMode=callIfNoReturn 模式下,如果没有指定返回参数,驱动程序将使用 CALL 语句(允许过程调用),否则驱动程序将使用 SELECT 语句。在 escapeSyntaxCallMode=call 模式下,驱动程序始终使用 CALL 语句(仅允许过程调用)。
正如您所看到的,{call something()}默认情况下所有语句都被视为函数调用,并且始终转换为 SELECT。设置escapeSyntaxCallMode为call将使驱动程序将它们转换为callSQL 语句。该callIfNoReturn选项对于大多数用例来说似乎是最合理的,因为如果未指定返回参数,它将把 JDBC 调用转换为存储过程调用,否则转换为函数调用。
您可以在 Postgres 文档中找到使用此设置的示例(第 6 章。调用存储函数和过程):
Run Code Online (Sandbox Code Playgroud)// set up a connection String url = "jdbc:postgresql://localhost/test"; Properties props = new Properties(); // ... other properties ... // Ensure EscapeSyntaxCallmode property set to support procedures if no return value props.setProperty("escapeSyntaxCallMode", "callIfNoReturn"); Connection con = DriverManager.getConnection(url, props); // Setup procedure to call. Statement stmt = con.createStatement(); stmt.execute("CREATE TEMP TABLE temp_val ( some_val bigint )"); stmt.execute("CREATE OR REPLACE PROCEDURE commitproc(a INOUT bigint) AS '" + " BEGIN " + " INSERT INTO temp_val values(a); " + " COMMIT; " + " END;' LANGUAGE plpgsql"); stmt.close(); // As of v11, we must be outside a transaction for procedures with transactions to work. con.setAutoCommit(true); // Procedure call with transaction CallableStatement proc = con.prepareCall("{call commitproc( ? )}"); proc.setInt(1, 100); proc.execute(); proc.close();>-- https://jdbc.postgresql.org/documentation/head/callproc.html#call-procedure-example
| 归档时间: |
|
| 查看次数: |
4904 次 |
| 最近记录: |