【问题标题】:Empty ResultSet from PL/SQL procedure returning non-empty rows来自 PL/SQL 过程的空 ResultSet 返回非空行
【发布时间】:2016-12-17 05:26:17
【问题描述】:

我使用JDBC 从使用SYS_REFCURSOR 的Oracle 存储过程中获取结果。当我在 sqlPlus 中执行存储过程时,我得到了 results ,但在 Java 中,我得到了一个空的结果集。

我在下面找到了问题here,这似乎是完美的解决方案,只是它不起作用。

根据我的日志 - 这是构建的最终字符串: 拨打ENT_GET_USERS(?,?,?,?)

谁能建议我为什么通过 Java 得到一个空的结果集?

我正在使用stmt.registerOutParameter(columnName, OracleTypes.CURSOR);

按照上面链接的建议,我将代码更改为为字符串参数设置""

case Types.VARCHAR:
                            if (inputValue != null)
                                stmt.setString(columnName, inputValue);
                            else
                                stmt.setString(columnName, "");

我的过程定义如下所示:

   CREATE OR REPLACE PROCEDURE ENT_GET_USERS(  p_id VARCHAR2 ,  p_id_type VARCHAR2,  p_app_id VARCHAR2 , usr_result OUT SYS_REFCURSOR ) 

EDIT1: 我在下面这样从 sqlplus 调用

SQL> variable rc refcursor;

SQL> exec ENT_GET_USERS(NULL , 'APP' , NULL , :rc ) ;

PL/SQL 过程成功完成。

SQL> 打印 rc ; // 这会返回结果

EDIT2: 我创建了一个测试程序,并使用了一个缩短版本的程序,但没有运气。代码如下:

             CallableStatement cstmt = conn
                .prepareCall("{call ETTRDV_EMEA.ENT_GET_USERS (?,?,?,?)}");

        cstmt.registerOutParameter("usr_result", OracleTypes.CURSOR); // REF CURSOR

        cstmt.setString("p_id", "-1");
        cstmt.setString("p_id_type", "APP");
        cstmt.setString("p_app_id", "");

      cstmt.execute(); //updated

        ResultSet rs = (ResultSet)cstmt.getObject("usr_result");

        while (rs.next()){
            System.out.println("Next");
        }

输出:Next next.. etc - 它有效!

步骤如下:

CREATE OR REPLACE PROCEDURE ENT_GET_USERS(  p_id VARCHAR2 ,  
                                            p_id_type VARCHAR2,  
                                            p_app_id VARCHAR2 , 
                                            usr_result OUT SYS_REFCURSOR) AS
BEGIN
OPEN usr_result for SELECT USR.USR_ID , USR.USR_SID, USR.USR_FIRSTNAME , USR.USR_LASTNAME , USR.REFERENCE_ID , USR.USR_CREATED_BY , USR.USR_CREATED_ON , USR.USR_UPDATED_BY , USR.USR_UPDATED_ON
                              FROM ENT_USERS USR ;
END;

并从 SQLPLUS 执行:

exec ENT_GET_USERS('-1' , 'APP' , '', :rc ) ;

这给了我预期的结果。

我做错了什么?

EDIT3: 更新了上面的工作代码。

【问题讨论】:

  • 您可以使用setNull() 而不是传递一个空字符串,以使其更加明确。如果没有看到您的数据、过程中的查询或实际绑定的参数值,很难说。但是您的 SQL*Plus 会话中的数据是否已提交?
  • 我最初使用的是 setNull()。那也行不通。数据被提交,因为它是由我用来获取的同一个程序插入的,而 sqlplus 是一个不同的会话,它给了我结果。
  • 您看到了什么 - 只是打印“无结果”?你的真实代码是否在做同样的测试?这就是它应该做的——执行结果应该是假的。
  • 为什么会是假的?来自文档 - “如果第一个结果是 ResultSet 对象,则为 true;如果第一个结果是更新计数或没有结果,则为 false”
  • 过程调用没有结果。其中一个输出参数是结果集(光标),但这不是第一个结果。

标签: java stored-procedures jdbc oracle11g


【解决方案1】:

布尔结果应该为假;这并不意味着 ref 光标为空。 From the documentation:

execute 方法返回一个布尔值来指示第一个结果的形式。您必须调用方法 getResultSet 或 getUpdateCount 来检索结果;您必须调用 getMoreResults 才能移动到任何后续结果。

回报:
如果第一个结果是 ResultSet 对象,则为 true;如果第一个结果是更新计数或没有结果,则返回 false

过程调用没有结果。返回值与此调用恰好具有并且恰好是游标的 out 参数是否包含任何内容无关。

由于您已在 SQL*Plus 中尝试过此操作,此时基本上就像您已经完成了 exec,但您还没有对 :rc 进行任何操作。

您需要获取光标,例如:

ResultSet rset = cstmt.getCursor("usr_result");

或者因为您没有使用 OracleCallableStatement:

ResultSet rset = (ResultSet) cstmt.getObject("usr_result");

然后像使用从查询创建的结果集一样迭代结果集。


命名参数的结果好坏参半,尤其是在以与定义它们的顺序不同的顺序设置它们时。您可能会发现需要使用getCursor(4)getObject(4)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-19
    • 1970-01-01
    • 2015-12-09
    • 2011-08-22
    • 2021-03-18
    • 1970-01-01
    • 2015-10-13
    • 1970-01-01
    相关资源
    最近更新 更多