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

JDBC调用存储过程返回无结果集报错,Hibernate调用正常排查

JDBC调用存储过程报错问题排查

问题场景

使用JDBC调用存储过程时触发SQLServerException,但相同逻辑用Hibernate调用则无异常。

JDBC调用代码

Connection con = DriverManager.getConnection("jdbc:sqlserver://myhost;databaseName=mydb;encrypt=false","user", "pass");
con.setAutoCommit(false);
CallableStatement cs = con.prepareCall("{call abc(?,?,?,?,?,?,?)}");
cs.setDate(1, java.sql.Date.valueOf(LocalDate.of(2023, 1, 10)));
cs.setDate(2, java.sql.Date.valueOf(LocalDate.of(2023, 1, 9)));
cs.setString(3, "PROD");
cs.registerOutParameter(4, Types.NUMERIC);
cs.registerOutParameter(5, Types.NUMERIC);
cs.registerOutParameter(6, Types.NUMERIC);
cs.registerOutParameter(7, Types.NUMERIC);
cs.executeQuery();

异常信息

2023-01-13T11:22:48.975-06:00 DEBUG 21888 --- [restartedMain]
c.m.s.jdbc.internals.SQLServerException : ***
SQLException:SQLServerCallableStatement:5
com.microsoft.sqlserver.jdbc.SQLServerException: The statement did not
return a result set. The statement did not return a result set.

Hibernate调用代码

StoredProcedureQuery query = em.createStoredProcedureQuery("abc")
        .registerStoredProcedureParameter(
                "date1",
                LocalDate.class,
                ParameterMode.IN
                )
        .registerStoredProcedureParameter(
                "date2",
                LocalDate.class,
                ParameterMode.IN
                )
        .registerStoredProcedureParameter(
                "name",
                String.class,
                ParameterMode.IN
                )
        .registerStoredProcedureParameter(
                "value1",
                BigDecimal.class,
                ParameterMode.OUT
                )
        .registerStoredProcedureParameter(
                "value2",
                BigDecimal.class,
                ParameterMode.OUT
                )
        .registerStoredProcedureParameter(
                "value3",
                BigDecimal.class,
                ParameterMode.OUT
                )
        .registerStoredProcedureParameter(
                "value4",
                BigDecimal.class,
                ParameterMode.OUT
                )
        .setParameter("date1", LocalDate.of(2023, 1, 10))
        .setParameter("date2", LocalDate.of(2023, 1, 9))
        .setParameter("name", "PROD");

query.execute();
log.info("value2 is {}", query.getOutputParameterValue("value2"));

驱动TRACE日志字节差异

JDBC发送的字节

03 01 02 26 00 5E 01 00 16 00 00 00 12 00 00 00   ...&.^..........
02 00 00 00 00 00 00 00 00 00 01 00 00 00 FF FF   ................
0A 00 00 00 00 00 E7 40 1F 09 04 D0 00 34 96 00   .......@.....4..
45 00 58 00 45 00 43 00 20 00 74 00 65 00 6D 00   E.X.E.C. .a.b.c.

Hibernate发送的字节

03 01 02 26 26 00 48 01 00 16 00 00 12 00 00 00   ...&.H..........
02 00 00 00 00 00 00 00 00 00 01 00 00 00 FF FF   ................
0A 00 00 00 00 00 E7 40 1F 09 04 D0 00 34 96 00   .......@.....4..
45 00 58 00 45 00 43 00 20 00 74 00 65 00 6D 00   E.X.E.C. .a.b.c.

问题分析与解决方案

核心问题

JDBC代码中调用了executeQuery(),这个方法仅适用于返回结果集的SQL语句,而你的存储过程只输出参数、不返回结果集,因此触发异常。

Hibernate的execute()方法会自动适配存储过程类型:对于无结果集、仅含输出参数的存储过程,它会选择合适的执行逻辑,不会强制要求返回结果集,所以能正常运行。

从TDS协议字节差异也能看出:

  • JDBC发送的5E(对应字符^)代表SQLExecDirect指令,强制期望返回结果集
  • Hibernate发送的48(对应字符H)代表SQLExecute指令,仅执行已准备的语句,不强制要求结果集

修改方案

将JDBC代码中的cs.executeQuery()替换为cs.execute(),之后通过getBigDecimal()等方法获取输出参数:

Connection con = DriverManager.getConnection("jdbc:sqlserver://myhost;databaseName=mydb;encrypt=false","user", "pass");
con.setAutoCommit(false);
CallableStatement cs = con.prepareCall("{call abc(?,?,?,?,?,?,?)}");
cs.setDate(1, java.sql.Date.valueOf(LocalDate.of(2023, 1, 10)));
cs.setDate(2, java.sql.Date.valueOf(LocalDate.of(2023, 1, 9)));
cs.setString(3, "PROD");
cs.registerOutParameter(4, Types.NUMERIC);
cs.registerOutParameter(5, Types.NUMERIC);
cs.registerOutParameter(6, Types.NUMERIC);
cs.registerOutParameter(7, Types.NUMERIC);

// 替换executeQuery()为execute()
cs.execute();

// 获取输出参数
BigDecimal value1 = cs.getBigDecimal(4);
BigDecimal value2 = cs.getBigDecimal(5);
BigDecimal value3 = cs.getBigDecimal(6);
BigDecimal value4 = cs.getBigDecimal(7);

// 后续业务处理...
con.commit();
con.close();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 00:46:02