【问题标题】:Determine if NHibernate Session is in an error state判断 NHibernate Session 是否处于错误状态
【发布时间】:2013-03-18 00:30:28
【问题描述】:

全部,

是否可以从会话对象(ISession,或其 ISessionImplementor)中确定是否发生错误?或者,是否可以连接一个在会话发生错误时调用的偶数处理程序?

我非常了解通过将代码包装在 try/catch 中并立即处理会话来处理带会话的模式。不过,在我的情况下,我已经实现了与会话范围等效的东西,它将休眠会话分发给在当前范围内运行的 DAO。当我发出休眠会话时,客户端代码仅使用它来运行持久操作,我不希望客户端负责进行会话清理,这是会话范围的责任。示例如下:

using (new SessionScope(SessionHelper.OpenSession()))
{
    // do read/write etc.
    // ex:
    mydao.MakePersistent(someEntity);  // <-- an error can occur here
} // implicit flush/clean up, BUT in order to do this correctly I have to know if the session in the scope has no errors!

如您所见,SessionScope 实现了 IDisposable,我在那里进行了会话终结,如刷新、tx.Commit() 和处置。但是,如果会话发生错误,我将无法刷新会话!

一种解决方法是不提供原始休眠会话,而是提供一个带有执行会话操作的方法的包装器对象,这样我就可以在 try/catch 中包装任何操作并知道错误发生的时间。如果你问我,那是愚蠢的解决方法。

另一个选项是所有 DAO 都通知我的会话范围发生了错误,这意味着我的所有 DAO 方法(在 catch 块中)必须检查是否定义了会话范围,如果是,它们负责会话失败 (scope.FailSession(session);) 这要好得多,但我必须在我的所有 DAO 中虔诚地这样做,如果我忘记了,我的会话范围将通过在错误会话上调用 session.Flush() 来行为不端。

感谢 Oskar B. 的评论,对于需要具有 ACID 属性或存在与持久性无关的异常风险的任何逻辑,都需要使用基于事务的方法。这是修改后的解决方案:

using (var txScope = new TransactionScope(SessionHelper.OpenSession()))
{
     Customer cust = mydao.getCustomer();
     Order order = mydao.getOrder(cust);
     // modify order, etc. (an error may occur at any time within this scope)
     txScope.VoteCommit();           
} // if we voted commit, it will flush/commit otherwise it will rollback 

【问题讨论】:

    标签: .net winforms nhibernate


    【解决方案1】:

    通常您会将事务与会话分开,因为我们通常希望应用程序代码确认事务提交(通过在没有异常的情况下到达 tx.Commit() 行)。然后会话范围的 Dispose() 就变成了简单的 session.Dispose()。

    一种方法是简单地将您对 scope.FailSession() 的想法替换为 scope.CompleteSession()。这与上述类似 - 如果您忘记它,将不会保存任何内容,问题将立即显现。

    通常,我们在更大的范围内处理会话 - 而不是在特定的 DAO 中,因为这使得在单个事务中执行“用户请求”的整个工作变得困难。通常当异常发生时,它会导致其余的域逻辑和其他“应用程序代码”被跳过。所以实际的异常处理和会话处理只需要出现在代码的一小部分。

    【讨论】:

    • 感谢您的贡献。我不确定我是否清楚,但上面定义的会话范围可以跨越的不仅仅是一个方法调用,例如在 Web 场景中,这可能跨越单个 Web 请求。我的 dao 基类有一个由所有 DAO 继承的会话属性。 session 属性只是返回 dao 的当前作用域的休眠会话。
    • 我决定使用 FailSession() 的想法毕竟有两个原因:1)我已经有一个 catch 块来捕获休眠异常并将它作为 PersistenceException 重新抛出(因此我的应用程序没有't reference hibernate) 2)我发现方法显式名称更能描述我的意图,并根据我是否失败会话让使用 stmt 提交/回滚
    • 如果其他地方发生异常会怎样?然后你还会提交一个半完成的事务吗?
    • 那么它是不相关的,不,永远不要提交那部分成功的东西。在我的 DAO 中,使用 try{ Persist(model); } catch (HibernateException e) { FailSession(sess);抛出新的 PersistenceException(e);我只捕获持久异常。任何其他异常都将导致会话上的默认清理行为,即 Rollback()。
    • 实际上,这很好,目前我所有的操作都是单个任务,因此它们要么成功要么失败,或者只是读取数据存储。 W / 读取,这并不重要,但是如果您在不同时间保留项目的更长事务,它确实如此。那时正确的做法是遵循 ACID。
    【解决方案2】:

    似乎唯一的方法是处理异常并处理它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-30
      • 1970-01-01
      • 2015-06-01
      • 2011-04-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多