通过 JDBC 调用 Sybase 存储过程时的空结果集

Posted

技术标签:

【中文标题】通过 JDBC 调用 Sybase 存储过程时的空结果集【英文标题】:Null resultsets when calling Sybase stored procedure through JDBC 【发布时间】:2013-02-12 09:18:57 【问题描述】:

我正在调用一个通过 JDBC 返回多个结果集的 Sybase 存储过程。 我需要获得一个特定的结果集,其中包含一个名为“结果”的列 这是我的代码:

CallableStatement cs = conn.prepareCall(sqlCall);
cs.registerOutParameter(1, Types.VARCHAR);
cs.execute();
ResultSet rs=null;
int count = 1;
boolean flag = true;
while (count < 20000 && flag == true) 
    cs.getMoreResults();
    rs = cs.getResultSet();
    if (rs != null) 
        ResultSetMetaData resultSetMetaData = rs.getMetaData();
        int columnsCount = resultSetMetaData.getColumnCount();
        if (resultSetMetaData.getColumnName(1).equals("Result")) 
            // action code resultset found 
            flag = false;
            // loop on the resultset and add the elements returned to an array list
            while (rs.next()) 
                int x = 1;
                while (x <= columnsCount) 
                   result.add(rs.getString(x));
                   x++;
                
            
            result.add(0, cs.getString(1));
        
    
    count++;

这里发生的是cs.getMoreResults 返回大量空结果集,直到它到达目标结果集。我不能使用cs.getMoreResults 作为循环条件,因为它为空结果集返回false。

我在没有返回想要的结果集的情况下设置了一个固定数字来结束循环,以防止它进入无限循环。它工作得很好,但我认为这是不对的。

我认为 Sybase select @variable = value 中的赋值返回的 null 结果集

以前有人遇到过这种情况吗?

【问题讨论】:

【参考方案1】:

您误解了getMoreResults() 的返回值。你也忽略了execute()的返回值,这个方法返回一个boolean表示第一个结果的类型:

true:结果是ResultSet false : 结果是更新计数

如果结果为true,则使用getResultSet() 检索ResultSet,否则使用getUpdateCount() 检索更新计数。如果更新计数为-1,则表示没有更多结果。请注意,当当前结果为ResultSet 时,更新计数也将为-1。如果没有更多结果或者结果是更新计数,那么知道getResultSet() 应该返回 null 也很好(最后一个条件就是为什么你会得到这么多 null 值)。

现在,如果您想检索更多结果,请调用getMoreResults()(或其兄弟接受int 参数)。 boolean 的返回值与execute() 的含义相同,所以false 不代表没有结果

只有在 getMoreResults() 返回 false 并且 getUpdateCount() 返回 -1 时才会没有更多结果(Javadoc 中也有记录)

本质上,这意味着如果您想正确处理所有结果,您需要执行以下操作:

boolean result = stmt.execute(...);
while(true) 
    if (result) 
        ResultSet rs = stmt.getResultSet();
        // Do something with resultset ...
     else 
        int updateCount = stmt.getUpdateCount();
        if (updateCount == -1) 
            // no more results
            break;
        
        // Do something with update count ...
    
    result = stmt.getMoreResults();

我的猜测是,在获得实际的 ResultSet 之前,您会获得大量更新计数。

我对 Sybase 不是很熟悉,但它的表亲 SQL Server 有一个“烦人”的功能,如果您没有明确地将 SET NOCOUNT ON; 放在存储过程的开头,它会从存储过程返回更新计数。

注意:这个答案的一部分是基于我对Execute “sp_msforeachdb” in a Java application的回答

【讨论】:

我在 Sql Server 上遇到了同样的问题,你的回答帮助我解决了这个问题。我无法弄清楚为什么带有一些数据的stmt.execute() 会返回false,即使我可以清楚地看到手动运行时返回的结果集中的数据。我仍然不确定我是否理解updateCount(),因为我不相信存储的过程实际上正在更新任何数据.. @Catfish 您也可以尝试在您的 sp 中添加 SET NOCOUNT ON 我无权修改存储过程。你的答案似乎对我有用。谢谢。

以上是关于通过 JDBC 调用 Sybase 存储过程时的空结果集的主要内容,如果未能解决你的问题,请参考以下文章

sybase存储过程中怎么调用存储过程

一个存储过程中调用另一个存储过程的问题(sybase数据库)

Sybase·调用存储过程并返回结果

将sybase存储过程作为链接服务器过程sql server 2008执行

SYBASE ASE上排查问题自定义存储过程

通过JDBC API调用存储过程的范例