从 java 调用时如何将 Cursor 变量传递给 postgres 过程?

How to pass Cursor variable to postgres proceudre while calling from java?

我正在从 spring 引导应用程序调用一个 postgres 存储过程,它有 1 个文本类型的 IN 参数和 1 个 refcursor 类型的 INOUT 参数。如何从 CallableStatement 以外的 spring 引导应用程序调用此过程。

public class CallProc {
    public static void main(String[] args) throws ClassNotFoundException, java.sql.SQLException {
        
        Class.forName("org.postgresql.Driver");
        
        String url = "jdbc:postgresql://azure.com/test";
        Properties props = new Properties();
        props.setProperty("user","test");
        props.setProperty("password","test");
        props.setProperty("ssl","true");
        props.setProperty("escapeSyntaxCallMode", "callIfNoReturn");
        Connection conn = DriverManager.getConnection(url, props);

        // need a transaction
        conn.setAutoCommit(false);

        java.sql.CallableStatement callableStatement =
            conn.prepareCall("{call myProc(?, ?)}");

        callableStatement.setString(1, "user");
        callableStatement.setObject(2, null);

        callableStatement.registerOutParameter(2, java.sql.Types.REF_CURSOR);

        callableStatement.execute();
       
        java.sql.ResultSet rs =
            (java.sql.ResultSet) callableStatement.getObject(2);

        while (rs.next())
            System.out.println(rs.getInt(1));

        rs.close();
        conn.commit();

        conn.close();
    }
}

我的过程定义是这样的,

CREATE OR REPLACE PROCEDURE myapp.MyProc(
     in_user_id TEXT,
     INOUT user_roles refcursor)
language plpgsql
AS $BODY$
DECLARE

DERIVED USER_ID VARCHAR(50);

BEGIN
//body
...
//
END
$BODY$

谢谢

要使用 java.sql.CallableStatement 调用过程,请使用值为 callcallIfNoReturn 的连接参数 escapeSyntaxCallMode,并且不指定 return 参数。正如 the documentation 所说:

escapeSyntaxCallMode = String

Specifies how the driver transforms JDBC escape call syntax into underlying SQL, for invoking procedures or functions. 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).

问题是在 v11 中添加过程之前,JDBC 驱动程序将 CallableStatement 调用转换为函数调用,这对过程不起作用。

这是调用过程 p(IN integer, INOUT refcursor) 的代码示例,其中 refcursorinteger 的结果集上:

public class CallProc {
    public static void main(String[] args) throws ClassNotFoundException, java.sql.SQLException {
        Class.forName("org.postgresql.Driver");

        java.sql.Connection conn =
            java.sql.DriverManager.getConnection(
                "jdbc:postgresql:test?user=laurenz&password=something&escapeSyntaxCallMode=callIfNoReturn"
            );

        // need a transaction
        conn.setAutoCommit(false);

        java.sql.CallableStatement callableStatement =
            conn.prepareCall("{call p(?::text, ?::refcursor)}");

        callableStatement.setInt(1, 5);
        callableStatement.setObject(2, null);

        callableStatement.registerOutParameter(2, java.sql.Types.REF_CURSOR);

        callableStatement.execute();
       
        java.sql.ResultSet rs =
            (java.sql.ResultSet) callableStatement.getObject(2);

        while (rs.next())
            System.out.println(rs.getInt(1));

        rs.close();
        conn.commit();

        conn.close();
    }
}