You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server存储过程被Java调用时无法返回结果集的问题求助

修复SQL Server存储过程调用时Java无法获取结果集的问题

这个问题我之前也碰到过,核心原因是:当你的存储过程里包含INSERT这类DML操作时,SQL Server会默认返回更新计数(也就是受影响的行数),这个结果会排在你需要的SELECT结果集前面。Java的execute()方法执行后,默认指向第一个返回的结果(也就是更新计数),而这并不是ResultSet,所以调用getResultSet()就会抛出"The statement did not return a result set"的异常。

下面给你两种靠谱的修复方案,你可以根据实际情况选择:

方案一:修改存储过程(推荐)

在存储过程的BEGIN块开头添加SET NOCOUNT ON;,这个语句会抑制SQL Server返回DML操作的更新计数,让存储过程只返回你需要的SELECT结果集。

修改后的存储过程代码:

create procedure spAddPerson @ID int, @Name nvarchar(50) 
as 
begin 
    SET NOCOUNT ON; -- 关键:关闭更新计数的返回
    create table #justTmp ( num int primary key, justName nvarchar(50) ) 
    if @ID in (select C.ContributorID from Contributors C) 
    begin 
        insert into #justTmp values (@ID, @Name) 
    end 
    select * from #justTmp 
end

修改后,Java代码不需要大改,只需要注意在获取结果集后先判断是否有数据(避免空指针):

CallableStatement cstmt = null; 
ResultSet rs = null; 
try {
    cstmt=conn.prepareCall("{ call spAddPerson(?,?) }"); 
    cstmt.setInt(1, 1); 
    cstmt.setString(2, "MyName"); 
    cstmt.execute(); 
    rs=cstmt.getResultSet(); 
    if (rs.next()) { // 先判断结果集是否有行
        int first=rs.getInt(1); 
        String second=rs.getString(2);
        // 这里处理你的数据逻辑
    }
} finally {
    // 务必关闭资源,防止内存泄漏
    if (rs != null) rs.close();
    if (cstmt != null) cstmt.close();
}

如果你的Java版本是7及以上,更推荐用try-with-resources自动关闭资源,代码更简洁安全:

try (CallableStatement cstmt = conn.prepareCall("{ call spAddPerson(?,?) }")) {
    cstmt.setInt(1, 1); 
    cstmt.setString(2, "MyName"); 
    cstmt.execute();
    
    try (ResultSet rs = cstmt.getResultSet()) {
        if (rs.next()) {
            int first = rs.getInt(1); 
            String second = rs.getString(2);
            // 处理数据
        }
    }
}

方案二:修改Java代码(不修改存储过程的情况)

如果因为权限或其他原因无法修改存储过程,你可以在Java代码中手动跳过所有更新计数,直到找到真正的结果集:

CallableStatement cstmt = null; 
ResultSet rs = null; 
try {
    cstmt = conn.prepareCall("{ call spAddPerson(?,?) }"); 
    cstmt.setInt(1, 1); 
    cstmt.setString(2, "MyName"); 
    boolean hasResultSet = cstmt.execute();
    
    // 跳过所有更新计数,直到找到结果集或者没有更多结果
    while (!hasResultSet && cstmt.getUpdateCount() != -1) {
        hasResultSet = cstmt.getMoreResults();
    }
    
    if (hasResultSet) {
        rs = cstmt.getResultSet(); 
        if (rs.next()) {
            int first = rs.getInt(1); 
            String second = rs.getString(2);
            // 处理数据
        }
    }
} finally {
    if (rs != null) rs.close();
    if (cstmt != null) cstmt.close();
}

这里的逻辑是:execute()返回的boolean表示第一个结果是不是ResultSet。如果是false,说明是更新计数,我们调用getUpdateCount()获取计数(这里可以忽略),然后用getMoreResults()切换到下一个结果,直到找到ResultSet或者没有更多结果(getUpdateCount()返回-1表示没有更多结果)。


内容的提问来源于stack exchange,提问作者Ori Lev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:23:35