查询出现异常后使用NHibernate会话



我们正在尝试实现重试逻辑,以从Azure环境中的瞬态错误中恢复。

我们使用长时间运行的会话来跟踪并提交应用程序事务结束时的一系列更改(可能分布在多个web请求中)。在此过程中,我们需要从数据库中获取额外的数据。我们的主要问题是,我们无法轻易地从数据库错误中恢复,因为我们无法"回放"所有用户操作。

到目前为止,我们使用了简单的恢复算法:

  • 尝试在长时间运行的会话中执行操作
  • 如果出现错误,请关闭会话,打开新会话并将实体合并到其中
  • 重试该操作

就时间而言,这是一种非常昂贵的方法(对于大型实体层次结构来说,合并确实很长)。所以我们想稍微优化一下。

我们希望在单独的会话中执行查询操作(以保持长时间运行的会话不受影响且安全),成功后,将结果合并回长时间运行会话。这里的重试相对简单——我们只需要打开新会话并再次运行查询。然而,使用这种方法,我们在初始化惰性属性/集合时遇到了一个问题:

  • 如果我们在单独的会话中这样做,我们需要合并回结果(许多实体),但合并可能会失败并中断长时间运行的会话
  • 我们尝试了不同的方法将原始实体"移动"到不同的会话,加载详细信息并将其返回,但没有成功(逐出、复制等)

有一条已知的语句,即在出现异常时应丢弃会话。但是,该示例显示写入操作。的仍然是真的吗?我的意思是,如果我保证没有数据被写回数据库,我可以重用同一个会话来再次运行查询吗?

关于长时间运行会话的重试逻辑,您还有其他建议吗?

IMO没有办法解决您的问题。提交所有内容需要花费大量时间,否则您将不得不做大量工作,将其分解为较小的会话,并处理合并时可能发生的每一个错误。

为了回答您关于在异常后使用会话的问题:您不能再信任此会话中的任何东西,甚至不能信任已加载的实体。

阅读Ayende的文章中的这一段,该文章关于在会话中出现异常时使用恢复计划构建一个简单的todo应用程序:

然后是错误处理的问题。如果出现异常(例如StaleObjectStateException,因为并发冲突),您的会话及其加载的实体是toast,因为NHibernate,从会话引发的异常将该会话移动到未定义的状态。您不能再使用该会话或任何已加载的实体。如果您只有一个全局会话,则意味着您可能需要重新启动应用程序,这可能不太好主意

最新更新