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

时间:2012-03-21 03:39:39

标签: c# nhibernate transactions unit-of-work

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

执行此操作的正确方法似乎是在构造函数中实例化ISessionITransaction,然后将其置于析构函数或Dispose()方法中。 / p>

当然,如果有人调用Save()方法,那么ISession会被刷新,而ITransaction会完整,所以在调用Save()后,就不会再次成为Save()的有效开放交易......除非我提交了第一笔交易并立即开立了另一笔新交易。但这是个好主意吗?

从设计角度来说,进行一次提交操作是有意义的,但我不一定能控制代码,而其他开发人员可能不会遵守UnitOfWork模式。

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

3 个答案:

答案 0 :(得分:11)

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

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

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

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

  • 这是一个UI应用程序
  • 只会在上次交易中刷新更改。

UI应用

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

更改仅在上次交易中刷新

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

简单方法(tm)

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

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

答案 1 :(得分:2)

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

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

public interface IAction
{    
    void Execute();
}

public abstract class Action<T> : IAction, IDisposable where T : Action<T>
{
    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<MyBusinessLogic>
{
    protected override void OnExecute()
    {
       //Implementation
    }
}

public class MyAnotherBusinessLogic : Action<MyAnotherBusinessLogic>
{
    protected override void OnExecute()
    {
        //Nested transaction
        MyBusinessLogic logic = new MyBusinessLogic();
        logic.Execute();
    }
}

答案 2 :(得分:0)

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

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();
  }
}