0

全部,

如果发生错误,是否可以从会话对象(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 
4

2 回答 2

0

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

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

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

于 2013-03-18T06:29:11.153 回答
0

看来唯一的方法是处理异常并处理它。

于 2013-03-22T01:11:15.073 回答