You need to enable JavaScript to run this app. Kotlin调用带INSERT操作的SQL存储过程时获取返回值结果集为null
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin调用带INSERT操作的SQL存储过程时获取返回值结果集为null

核心问题原因

你调用时拿到空ResultSet的核心原因,是SQL Server中DML操作生成的更新计数结果,挡在了后续SELECT结果的读取链路前面。

SQL Server JDBC驱动会严格按照存储过程内的语句执行顺序推送返回内容:

  • INSERT、UPDATE、DELETE这类DML语句执行完成后,会优先返回对应操作的更新计数(也就是本次操作影响了多少行),这类结果不属于ResultSet
  • 只有当SELECT语句执行完成后,才会生成可被读取的ResultSet

你现在的代码在execute()执行完之后直接读statement.resultSet,此时驱动推过来的第一个结果是INSERT产生的更新计数,根本没有关联对应的ResultSet,所以取出来就是null。如果把INSERT删掉,第一个推回来的结果就是SELECT生成的ResultSet,自然就能正常读到1234的值。

快速验证根因

你可以用驱动自带的返回值判断逻辑确认问题点:
保留INSERT语句时,调用statement.execute()的返回值是false,代表当前拿到的是更新计数而非ResultSet,这时候读statement.updateCount能拿到值为1的影响行数——说明流程还停留在处理INSERT结果的阶段,根本没走到SELECT生成ResultSet的环节。

两种落地解决方式

方案1:改存储过程(最省事,推荐)

在存储过程的BEGIN块开头加一行SET NOCOUNT ON。这行配置的作用就是告诉SQL Server,不要把DML语句的影响行数当成结果回传给调用端。

修改后的存储过程完整代码:

ALTER PROCEDURE [dbo].[TestProcedure]
    @varTest INT,
    @varTest2 INT
AS
BEGIN
    -- 新增配置,关闭更新计数回传
    SET NOCOUNT ON
    DECLARE @returnValue AS INT
    SET @returnValue = 1234
    INSERT INTO xTABLE(col1, col2)
    VALUES(1, 2)
    SELECT @returnValue AS returnValue 
    RETURN
END
GO

加上这行配置后,你原来的Kotlin代码一行都不用改,就能正常拿到非空的ResultSet,顺利读到returnValue=1234的结果。

方案2:调整Kotlin端的结果遍历逻辑(没法改存储过程时用)

按照JDBC的规范,调用方需要把所有返回结果遍历完、消费掉前置的更新计数,才能拿到后续的ResultSet。具体实现就是循环判断当前的返回类型,跳过所有更新计数结果,直到拿到目标ResultSet:

val statement = connection.prepareCall("{CALL TestProcedure (1, 1)}")
var currentIsResultSet = statement.execute()
var targetRs: ResultSet? = null
while (true) {
    if (currentIsResultSet) {
        // 当前返回的就是ResultSet,赋值后跳出循环
        targetRs = statement.resultSet
        break
    }
    // 读当前的更新计数
    val updateCount = statement.updateCount
    // updateCount等于-1代表没有更多返回结果了
    if (updateCount == -1) {
        break
    }
    // 继续获取下一个返回结果
    currentIsResultSet = statement.moreResults
}
// 拿到targetRs之后正常读returnValue即可
容易踩的混淆坑

别把存储过程的两类返回值搞混:

  • 你代码里SELECT @returnValue AS returnValue生成的是结果集,必须通过ResultSet读取
  • 存储过程末尾RETURN返回的整数是存储过程的状态返回码,需要用{?= CALL TestProcedure(?, ?)}的格式注册输出参数才能读取,和ResultSet是两套独立的返回机制,不要混同。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.26 02:15:04