"x is a procedure, use "当我已经在使用呼叫时呼叫""
"x is a procedure, use "call"" when I am already using call
我正在使用 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;
$$;
如果我在命令行上打开 psql 并且 运行 call reduceStock(1,1);
它会完美运行
然而,从我的 Java 程序调用它如下:
CallableStatement stmt = conn.prepareCall("{call reduceStock(?, ?)}");
stmt.setInt(1, productID);
stmt.setInt(2, quantity);
stmt.execute();
给我以下错误:
我试过的
来自 psql 客户端的 - 运行ning
call reduceStock(1,1);
- 完美运行
- 删除数据库并重新开始查看是否缓存了一些旧定义 - 没有用
- 大小写不同,间距
call
如有任何想法,我们将不胜感激
您需要删除大括号,这是调用过程的 JDBC 转义符。但是因为 Postgres 有它自己的 call
命令,所以不需要它们(并且与 JDBC 转义符冲突)。
CallableStatement stmt = conn.prepareCall("call reducestock(?, ?)");
过程 inocation ({call reduceStock(?, ?)}
) 周围的大括号表示这不是原生 SQL,而是 JDBC 语法。您可以在这里阅读更多相关信息:Why do JDBC calls to stored procedures wrap the call in curly brackets?.
因此,像这样的调用仍然需要由 JDBC 驱动程序转换为本机 SQL。默认情况下,Postgres 驱动程序会将此类语句视为函数调用并将它们转换为 SELECT reduceStock(?, ?)
SQL 查询。这不是在 Postgres 中调用存储过程的方式。在 Postgres 中,存储过程调用 SQL 是 call reduceStock(?, ?)
.
使其工作的一种方法是,如 @a_horse_with_no_name wrote in ,删除大括号。这使该语句成为本机调用,并且因为它是有效的 Postgres SQL 这将起作用。缺点是它不太跨平台,因为它不适用于不支持 call procname()
语法的数据库。例如,这不适用于 Oracle,因此如果您必须支持多个 JDBC 驱动程序,这是不太可取的方法。
更好的解决方法是提示 Postgres JDBC 驱动程序将此语法视为存储过程调用而不是函数调用,并将其相应地转换为 SQL。为此,Postgres 驱动程序也公开了一个 escapeSyntaxCallMode configuration property (check out the EscapeSyntaxCallMode enum):
Specifies how the driver transforms JDBC escape call syntax into underlying SQL, for invoking procedures or functions. (backend >= 11) In escapeSyntaxCallMode=select mode (the default), the driver always uses a SELECT statement (allowing function invocation only). In escapeSyntaxCallMode=callIfNoReturn mode, the driver uses a CALL statement (allowing procedure invocation) if there is no return parameter specified, otherwise the driver uses a SELECT statement. In escapeSyntaxCallMode=call mode, the driver always uses a CALL statement (allowing procedure invocation only).
如您所见,默认情况下,所有 {call something()}
语句都被视为函数调用,并且始终转换为 SELECT。将 escapeSyntaxCallMode
设置为 call
将使驱动程序将它们转换为 call
SQL 语句。 callIfNoReturn
选项对于大多数用例来说似乎是最合理的,因为如果没有指定 return 参数,它将把 JDBC 调用转换为存储过程调用,否则将转换为函数调用。
您可以在 Postgres 文档 (Chapter 6. Calling Stored Functions and Procedures) 中找到使用此设置的示例:
// 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
我正在使用 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;
$$;
如果我在命令行上打开 psql 并且 运行 call reduceStock(1,1);
然而,从我的 Java 程序调用它如下:
CallableStatement stmt = conn.prepareCall("{call reduceStock(?, ?)}");
stmt.setInt(1, productID);
stmt.setInt(2, quantity);
stmt.execute();
给我以下错误:
我试过的
-
来自 psql 客户端的
- 运行ning
call reduceStock(1,1);
- 完美运行 - 删除数据库并重新开始查看是否缓存了一些旧定义 - 没有用
- 大小写不同,间距
call
如有任何想法,我们将不胜感激
您需要删除大括号,这是调用过程的 JDBC 转义符。但是因为 Postgres 有它自己的 call
命令,所以不需要它们(并且与 JDBC 转义符冲突)。
CallableStatement stmt = conn.prepareCall("call reducestock(?, ?)");
过程 inocation ({call reduceStock(?, ?)}
) 周围的大括号表示这不是原生 SQL,而是 JDBC 语法。您可以在这里阅读更多相关信息:Why do JDBC calls to stored procedures wrap the call in curly brackets?.
因此,像这样的调用仍然需要由 JDBC 驱动程序转换为本机 SQL。默认情况下,Postgres 驱动程序会将此类语句视为函数调用并将它们转换为 SELECT reduceStock(?, ?)
SQL 查询。这不是在 Postgres 中调用存储过程的方式。在 Postgres 中,存储过程调用 SQL 是 call reduceStock(?, ?)
.
使其工作的一种方法是,如 @a_horse_with_no_name wrote in call procname()
语法的数据库。例如,这不适用于 Oracle,因此如果您必须支持多个 JDBC 驱动程序,这是不太可取的方法。
更好的解决方法是提示 Postgres JDBC 驱动程序将此语法视为存储过程调用而不是函数调用,并将其相应地转换为 SQL。为此,Postgres 驱动程序也公开了一个 escapeSyntaxCallMode configuration property (check out the EscapeSyntaxCallMode enum):
Specifies how the driver transforms JDBC escape call syntax into underlying SQL, for invoking procedures or functions. (backend >= 11) In escapeSyntaxCallMode=select mode (the default), the driver always uses a SELECT statement (allowing function invocation only). In escapeSyntaxCallMode=callIfNoReturn mode, the driver uses a CALL statement (allowing procedure invocation) if there is no return parameter specified, otherwise the driver uses a SELECT statement. In escapeSyntaxCallMode=call mode, the driver always uses a CALL statement (allowing procedure invocation only).
如您所见,默认情况下,所有 {call something()}
语句都被视为函数调用,并且始终转换为 SELECT。将 escapeSyntaxCallMode
设置为 call
将使驱动程序将它们转换为 call
SQL 语句。 callIfNoReturn
选项对于大多数用例来说似乎是最合理的,因为如果没有指定 return 参数,它将把 JDBC 调用转换为存储过程调用,否则将转换为函数调用。
您可以在 Postgres 文档 (Chapter 6. Calling Stored Functions and Procedures) 中找到使用此设置的示例:
// 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