你能在nhibernate的一个会话中发生多个事务吗? 这是一个坏主意吗?

我正在考虑为NHibernate持久层创建自己的IUnitOfWork实现。

似乎正确的方法是在构造函数中实例化ISessionITransaction ,然后在析构函数或Dispose()方法中进行Dispose()

当然,如果有人调用Save()方法,那么ISession将被刷新并且ITransaction将完成,因此在调用Save() ,将再次没有有效的打开事务来Save() …除非我提交了第一笔交易并立即开启了另一笔新交易。 但这是个好主意吗?

在设计方面,进行一次提交操作是有意义的,但我不一定能控制代码,而其他开发人员可能对遵循UnitOfWork模式不那么严格。

通过尝试使UnitOfWork容忍每个会话的多个事务,我会失去/获得任何东西吗? 我应该检查一个打开的事务,如果它已经被提交则抛出exception,而不是进行新的事务吗?

回答第一个问题:是的,可以在一个会话中拥有多个事务。

是个好主意吗? 这取决于。

问题是第一个事务中的数据更改将被提交,而不确定整个工作单元(会话)是否在最后提交。 当你得到一个稍后的事务中的StaleObjectException时,你已经提交了一些数据。 请注意,这种exception使您的会话无法使用,无论如何您必须销毁它。 然后很难重新开始并再试一次。

我想说,在这种情况下它运作良好:

  • 它是一个UI应用程序
  • 更改仅在最后一个事务中刷新。

UI应用程序

错误由用户以交互方式处理。 这意味着用户可以查看错误情况下实际存储的内容并重复他所做的更改。

更改仅在最后一个事务中刷新

由NH实施的会话仅在最后或“必要时”刷新更改。 因此,在会话提交之前,可以保留内存中的更改。 问题是NH需要在每次查询之前刷新会话,这很难控制。 它可以关闭,这会导致副作用。 在编写简单的事务时,您可以控制它。 在复杂的系统中,几乎不可能确保没有任何问题。

简单方法(tm)

我写了一个非常大的客户端 – 服务器系统的持久层。 在这样的系统中,您没有用户直接处理错误。 您需要处理系统中的错误并以一致的状态将控制权返回给客户端。

我将整个事务处理简化为绝对最小化,以使其稳定并且“白痴certificate”。 我总是创建一个会话和一个事务,它会被提交或不提交。

有多个选项可用于实现具有工作单元的nhibernate嵌套事务。

在这里,我使用Command模式作为工作单元。

 public interface IAction { void Execute(); } public abstract class Action : IAction, IDisposable where T : Action { public void Execute() { try { //Start unit of work by your unit of work pattern or transaction.Begin(); OnExecute(); //End Unit of work transaction.Commit(); } catch (Exception e) { transaction.Rollback(); throw e; } } protected abstract void OnExecute(); public void Dispose() { } } public class MyBusinessLogic : Action { protected override void OnExecute() { //Implementation } } public class MyAnotherBusinessLogic : Action { protected override void OnExecute() { //Nested transaction MyBusinessLogic logic = new MyBusinessLogic(); logic.Execute(); } } 

我认为每单位工作一次交易的解决方案限制性太强。 在某些环境中,人们可能需要能够在每个会话中执行多个事务。 我自己明确地管理交易,它似乎是一个灵活的解决方案。

 public interface IUnitOfWork: IDisposable { IGenericTransaction BeginTransaction(); } public interface IGenericTransaction: IDisposable { void Commit(); void Rollback(); } public class NhUnitOfWork: IUnitOfWork { private readonly ISession _session; public ISession Session { get { return _session; } } public NhUnitOfWork(ISession session) { _session = session; } public IGenericTransaction BeginTransaction() { return new NhTransaction(_session.BeginTransaction()); } public void Dispose() { _session.Dispose(); } } public class NhTransaction: IGenericTransaction { private readonly ITransaction _transaction; public NhTransaction(ITransaction transaction) { _transaction = transaction; } public void Commit() { _transaction.Commit(); } public void Rollback() { _transaction.Rollback(); } public void Dispose() { _transaction.Dispose(); } } 

用法如下所示。 它很容易融入任何模式。

 public void Do(IUnitOfWork uow) { using (var tx = uow.BeginTransaction()) { // DAL calls tx.Commit(); } }