【问题标题】:Hsqldb - Return a Result Set from Stored ProcHsqldb - 从存储过程返回结果集
【发布时间】:2016-03-27 21:53:12
【问题描述】:

我试图在 HsqlDB 中调用一个存储过程并返回一个结果集

我的存储过程如下

    CREATE PROCEDURE p_getTeamTasksForLastXDays(IN teamId BIGINT, IN numberOfDays BIGINT) READS SQL DATA
  DYNAMIC RESULT SETS 1
  BEGIN ATOMIC
   declare curs cursor for select taskId, taskName from V_TASK_DETAILS;
   open curs;
  END;
  /;

我用来调用这个proc的Java和hibernate代码如下

public void getTaskExecutionLogs(Long teamId, Long numberOfDays) {
        LOG.info("Entered getTaskExecutionLogs Method - teamId:{}, numberOfDays: {}", teamId, numberOfDays);

        ProcedureCall procedureCall = currentSession().createStoredProcedureCall("p_getTeamTasksForLastXDays");
        procedureCall.registerParameter( TEAM_ID, Long.class, ParameterMode.IN ).bindValue( teamId );
        procedureCall.registerParameter( NUMBER_OF_DAYS, Long.class, ParameterMode.IN ).bindValue( numberOfDays );

        ProcedureOutputs outputs = procedureCall.getOutputs();
        ResultSetOutput resultSetOutput = (ResultSetOutput) outputs.getCurrent();

        List resultSetList = resultSetOutput.getResultList();

}

当我尝试调用这个过程时得到的错误如下

java.lang.ClassCastException: org.hibernate.result.internal.UpdateCountOutputImpl cannot be cast to org.hibernate.result.ResultSetOutput
    at com.mct.dao.database.impl.TaskDetailsDAOImpl.getTaskExecutionLogs(TaskDetailsDAOImpl.java:229)

当我尝试在 MySql 中调用存储过程时,完全相同的代码可以正常工作

非常感谢任何帮助

谢谢 达米安

【问题讨论】:

  • 第 229 行是 - ResultSetOutput resultSetOutput = (ResultSetOutput) outputs.getCurrent();

标签: java hibernate hsqldb


【解决方案1】:

ProcedureOutputs 是一个 interface 哪个 extends Outputs (source)。

ResultSetOutput 是一个 interface 哪个 extends Output (source)。 当你调用getCurrent()Outputs 时,你会得到一个Output (source)。

基本上,您希望转换是正确的,因为您将结果转换为Output 的子接口。你正在做的事情叫做downcast。来看看案例吧。

您想将一个对象投射到另一个对象。由于ResultSetOutputextendsOutput,因此可能会感到沮丧。由于向下转换可能是可能的,因此您不会收到编译时错误,并且在可能的情况下,例如在您调用 MySQL 中的存储过程的情况下,向下转换将成功。但是,当无法进行向下转换时,您会收到运行时异常。在我们的特殊情况下,向下转换是不可能的,因为.getOutputs 返回另一个分类,可能是另一个继承分支上的子接口,例如UpdateCountOutput

【讨论】:

  • 是的,这就是我在这里遇到的情况。相同的代码在 MySql 存储过程中可以 100% 正常工作,所以我想在 Hsqldb 中复制该过程以进行单元测试
  • outputs.getCurrent().getClass() 返回什么?
  • @Damo,如果你能找出那个对象的类是什么,那么你就能找到解决方案。
  • getCurrent().getClass() 为 Hsqldb 存储过程返回 org.hibernate.result.internal.UpdateCountOutputImpl。对于 MySql 存储过程,它返回 org.hibernate.result.internal.ResultSetOutputImpl
  • 另外 - 当在调试模式下对 Mysql 存储的 proc 运行时 - 我得到以下输出 - [DEBUG] [194]org.hibernate.result.internal.OutputsImpl[buildOutput] - Building Return [isResultSet=真,updateCount=-1,extendedReturn=假。对于调试模式下的 Hsqldb 存储过程 - 我得到这个输出 - [DEBUG] [194]org.hibernate.result.internal.OutputsImpl[buildOutput] - Building Return [isResultSet=false, updateCount=0, extendedReturn=false
【解决方案2】:

Lajos 关于沮丧是正确的。问题是您在编码时假设ProcedureOutputs.getCurrent() 返回的Output 将是ResultSetOutput,而实际上它可能是UpdateCountOutput

其实Output接口有一个方法isResultSet()可以帮你判断:

布尔型 org.hibernate.result.Output.isResultSet()

确定此返回是否为结果(可转换为ResultSetOutput)。另一种方法是它是一个更新计数(可转换为UpdateCountOutput)。

返回:

true 表示可以安全地转换为ResultSetOutput),否则可以转换为UpdateCountOutput

除此之外,Outputs 可以传递多个OutputOutput.getCurrent() 的状态由Output.goToNext() 控制。

因此,为了正确处理多个结果,您必须通过以下方式获取输出:

ProcedureOutputs outputs = procedureCall.getOutputs();

do {
    Output current = outputs.getCurrent();

    if (current.isResultSet()) {
        ResultSetOutput resultSetOutput = (ResultSetOutput) current;
        System.out.println("do something with result set output");
    } else {
        UpdateCountOutput updateCountOutput = (UpdateCountOutput) current;
        System.out.println("do something with update count output");
    }            
} while (outputs.goToNext());

outputs.release();

在我的测试中我得到:

1647 [main] 调试 org.hibernate.SQL - {调用 p_getTeamTasksForLastXDays(?,?)}

休眠:{调用 p_getTeamTasksForLastXDays(?,?)}

1668 [main] 调试 org.hibernate.result.internal.OutputsImpl - 构建返回 [isResultSet=false, updateCount=0, extendedReturn=false

对更新计数输出做一些事情

1669 [main] 调试 org.hibernate.result.internal.OutputsImpl - 构建返回 [isResultSet=true, updateCount=-1, extendedReturn=false

1671 [main] DEBUG org.hibernate.loader.Loader - 结果集行:0

1671 [main] DEBUG org.hibernate.loader.Loader - 结果行:

对结果集输出做一些事情

PS:我这里没有mysql,所以我无法确认它是否同时返回ResultSetOutputUpdateCountOutput,但顺序与hsqldb不同,但也许你可以验证一下。

【讨论】:

  • 感谢您的帮助 - 这确实解决了问题。查看上面的代码示例 - Hsqldb 首先返回 UpdateCountOutput 结果,然后返回 ResultSetOutput。 Mysql首先返回ResultSetOutput,其次是UpdateCountOutput
  • “输出可以传递多个输出”,为什么一个存储过程会产生多个输出?
猜你喜欢
  • 1970-01-01
  • 2011-03-20
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 2013-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多