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