在 Java 中,调用 PostgreSQL 函数时,为什么会收到错误消息,告知该函数不存在?

Ren*_*ani 2 java postgresql stored-procedures sqlexception plpgsql

我在数据库中有这个程序:

CREATE OR REPLACE FUNCTION replacePageRelevance(id INT, value REAL) RETURNS VOID AS $$
BEGIN
INSERT INTO pageRelevance VALUES (id,value);
EXCEPTION WHEN unique_violation THEN
    UPDATE pageRelevance SET relevance = value WHERE pageId = id;       
END
$$
LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

以及调用此函数的这段代码:

try (CallableStatement cstm = conn.prepareCall(PAGE_RELEVANCE_SQL)) {
        for (Map.Entry<Integer, Double> entry : weightMap.entrySet()) {
            cstm.setInt(1, entry.getKey());
            cstm.setDouble(2, entry.getValue());
            cstm.addBatch();
        }
        cstm.executeBatch();
    } catch (SQLException e) {
        LOGGER.error("Error discovering pages relevance: " + e.getNextException());
    }
}
Run Code Online (Sandbox Code Playgroud)

这不起作用,我收到一个错误通知function replacepagerelevance(integer, double precision) doesn't exists.。为什么?

生成的调用是这样的:SELECT replacePageRelevance('882','8.0')。如果我在 pgAdmin 中执行它,它可以工作,但不能从 Java 中执行。

Grz*_*ski 5

这是因为您的 PL/pgSQL 函数定义为:

replacePageRelevance(id INT, value REAL)
Run Code Online (Sandbox Code Playgroud)

REAL是单精度浮点数,但在 Java 方面,您试图将它用作双精度,并且没有针对这种情况的隐式转换。

您应该更喜欢使用CallableStatement.setFloat单精度REAL数据类型,但它不是很清楚,因为阅读 Java API:

将指定参数设置为给定的 Java 浮点值。驱动程序在将其发送到数据库时将其转换为 SQL FLOAT 值。

由于FLOAT是Postgres 中的同义词DOUBLE PRECISION因此它的运行效果与CallableStatement.setDouble产生错误消息的效果相同(这很奇怪)。

当然,您可以将您的功能更改为replacePageRelevance(id INT, value DOUBLE PRECISION),正如我检查的那样,它与您的代码运行良好。

尽管如此,如果您想保留REAL在您的函数中),请使用如下所示的显式转换:

String PAGE_RELEVANCE_SQL = "{call replacePageRelevance(?, ?::real)}";
Run Code Online (Sandbox Code Playgroud)