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

Hibernate 5调用MSSQL存储过程报错:无法获取输出参数与结果集

解决Hibernate/Spring Data调用存储过程无法获取输出参数和结果集的问题

首先我得先拆解下你的存储过程逻辑:你调用udo_ui.PR_GetDocuments时,通过输出参数@rec拿到总记录数,存储过程本身的返回值存在@ret里,最后还额外SELECT @ret,@rec输出这两个值。所以实际调用后会产生三个关键内容:存储过程的返回值、输出参数iTotRecCount、还有一个包含两列的结果集。

你的代码问题主要出在这几个地方:

  • 没有注册存储过程的返回值参数,Hibernate需要显式声明才能获取这个值
  • 只依赖execute()的返回值判断结果,但execute()返回false是因为存储过程执行后第一个返回的不是结果集(而是返回值/输出参数),导致Hibernate误认为没有结果集
  • 输出参数的获取时机不对,有些数据库需要先读取结果集才能拿到输出参数的值

修正后的Hibernate代码示例

EntityManager manager = ...; // 注入或获取EntityManager

StoredProcedureQuery storedProcedure = manager.createStoredProcedureQuery("udo_ui.PR_GetDocuments")
    // 重点:存储过程的返回值必须第一个注册,索引为0
    .registerStoredProcedureParameter(0, Integer.class, ParameterMode.RETURN)
    // 注册输出参数
    .registerStoredProcedureParameter("iTotRecCount", Integer.class, ParameterMode.OUT)
    // 注册输入参数
    .registerStoredProcedureParameter("iFirstRecNo", Integer.class, ParameterMode.IN)
    .registerStoredProcedureParameter("iRetRecCount", Integer.class, ParameterMode.IN)
    .registerStoredProcedureParameter("department_id", Integer.class, ParameterMode.IN);

// 设置输入参数
storedProcedure.setParameter("iFirstRecNo", 18)
               .setParameter("iRetRecCount", 50)
               .setParameter("department_id", 181);

// 直接获取结果集,自动触发存储过程执行(不用单独调用execute())
List<Object[]> resultList = storedProcedure.getResultList();

// 获取存储过程的返回值(对应你的@ret)
Integer retValue = (Integer) storedProcedure.getOutputParameterValue(0);
// 获取输出参数iTotRecCount(对应你的@rec)
Integer recValue = (Integer) storedProcedure.getOutputParameterValue("iTotRecCount");

// 处理最后SELECT语句返回的结果集(里面也是@ret和@rec,和上面的值一致)
if (!resultList.isEmpty()) {
    Object[] row = resultList.get(0);
    Integer selectRet = (Integer) row[0];
    Integer selectRec = (Integer) row[1];
    System.out.println("SELECT返回的ret: " + selectRet + ", rec: " + selectRec);
}

System.out.println("存储过程返回值ret: " + retValue + ", 输出参数rec: " + recValue);

如果存储过程内部还有Documents结果集

假设PR_GetDocuments内部还会返回Documents的核心数据集,那会存在多个结果集,你需要依次获取:

// 第一个结果集:Documents数据
List<Object[]> documents = storedProcedure.getResultList();
// 第二个结果集:最后SELECT的@ret和@rec
List<Object[]> retRecResult = storedProcedure.getNextResult();

// 之后再获取返回值和输出参数
Integer retValue = (Integer) storedProcedure.getOutputParameterValue(0);
Integer recValue = (Integer) storedProcedure.getOutputParameterValue("iTotRecCount");

Spring Data JPA简化版(用@Procedure注解)

如果想用Spring Data的方式,可以定义Repository接口:

@Repository
public interface DocumentRepository extends JpaRepository<Document, Long> {

    @Procedure(procedureName = "udo_ui.PR_GetDocuments")
    Integer callPR_GetDocuments(
        @Param("iTotRecCount") Out<Integer> iTotRecCount,
        @Param("iFirstRecNo") Integer iFirstRecNo,
        @Param("iRetRecCount") Integer iRetRecCount,
        @Param("department_id") Integer departmentId
    );
}

调用时:

// 创建Out参数接收总记录数
Out<Integer> totRecCount = new Out<>(Integer.class);
// 调用存储过程,返回值就是@ret
Integer retValue = documentRepository.callPR_GetDocuments(totRecCount, 18, 50, 181);
// 从Out参数中取出@rec的值
Integer recValue = totRecCount.getValue();

System.out.println("存储过程返回值ret: " + retValue + ", 输出参数rec: " + recValue);

关键注意点

  1. 返回值必须最先注册:Hibernate对存储过程的参数顺序有严格要求,返回值参数要放在第一个位置,索引为0
  2. 优先用getResultList():不要依赖execute()的返回值判断结果集,直接调用getResultList()会自动触发执行并处理结果
  3. 结果集先于输出参数获取:部分数据库(比如SQL Server)需要先读取完所有结果集,才能正确获取输出参数的值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:34:30