调用Hibernate ProcedureOutputs.getCurrent()抛出NoMoreReturnsException的原因及触发条件
问题原因与解决方案
1. 异常触发原因
你的存储过程是仅执行更新操作、无返回结果集和输出参数的DML存储过程,但代码中使用do-while循环反复尝试获取输出内容。当存储过程的所有返回项(更新计数、结果集、输出参数)都被处理完毕后,再调用outputs.getCurrent()就会抛出NoMoreReturnsException——因为已经没有更多可返回的内容了。
Hibernate对存储过程返回内容的处理顺序是:先处理结果集,再处理输出参数,最后处理更新计数。如果存储过程只有更新操作,没有结果集和输出参数,那么仅会返回一个更新计数,处理完这个计数后就没有后续内容了,此时继续调用getCurrent()就会触发异常。
2. 异常触发的常见条件
- 存储过程仅执行DML操作(UPDATE/INSERT/DELETE),无结果集返回、无输出参数定义,代码却在处理完更新计数后仍尝试调用
getCurrent() - 遍历
ProcedureOutputs时,未先通过outputs.hasNext()判断是否还有返回项,直接调用getCurrent() - 错误认为无返回的存储过程会有额外输出内容,导致循环次数超出实际返回项数量
3. 修正后的代码
针对仅执行更新的存储过程,正确的调用方式是先判断是否有下一个返回项,处理完成后移动到下一项,直到没有更多内容:
Session session2 = HibernateUtil.getCurrentSession(); ProcedureCall call = session2.createStoredProcedureCall("UPDATE_PERSONAL_ADDRESS"); call.registerParameter(1, String.class, ParameterMode.IN).bindValue(staffNo); ProcedureOutputs outputs = call.getOutputs(); while (outputs.hasNext()) { Output output = outputs.getCurrent(); // 处理更新计数,获取受影响行数 if (output instanceof UpdateCountOutput) { UpdateCountOutput updateOutput = (UpdateCountOutput) output; int affectedRows = updateOutput.getUpdateCount(); // 可根据需求记录或使用受影响行数 } // 移动到下一个返回项 outputs.next(); } // 释放输出资源 outputs.release();
如果确认存储过程不会返回结果集或输出参数,也可以简化为:
Session session2 = HibernateUtil.getCurrentSession(); ProcedureCall call = session2.createStoredProcedureCall("UPDATE_PERSONAL_ADDRESS"); call.registerParameter(1, String.class, ParameterMode.IN).bindValue(staffNo); ProcedureOutputs outputs = call.getOutputs(); // 仅处理更新计数 if (outputs.hasNext()) { UpdateCountOutput updateOutput = (UpdateCountOutput) outputs.getCurrent(); int affectedRows = updateOutput.getUpdateCount(); outputs.next(); } outputs.release();
补充说明
SQL Server的DML存储过程默认会返回更新计数(受影响的行数),这是Hibernate会处理的唯一返回项。如果你的存储过程中添加了SET NOCOUNT ON;语句,这个更新计数会被取消,此时outputs.hasNext()会直接返回false,不会进入循环,也能避免异常。
内容的提问来源于stack exchange,提问作者user1169587
相关产品推荐
相关产品推荐

