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);
关键注意点
- 返回值必须最先注册:Hibernate对存储过程的参数顺序有严格要求,返回值参数要放在第一个位置,索引为0
- 优先用getResultList():不要依赖
execute()的返回值判断结果集,直接调用getResultList()会自动触发执行并处理结果 - 结果集先于输出参数获取:部分数据库(比如SQL Server)需要先读取完所有结果集,才能正确获取输出参数的值
内容的提问来源于stack exchange,提问作者avalon
相关产品推荐
相关产品推荐

