【问题标题】:can you have multiple transactions occur inside one session in nhibernate? And is it a bad idea?您可以在 nhibernate 的一个会话中发生多个事务吗?这是一个坏主意吗?
【发布时间】:2012-03-21 03:39:38
【问题描述】:

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

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

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

在设计方面,做一次提交操作是有意义的,但我不一定能控制代码,其他开发人员可能不太遵守 UnitOfWork 模式。

试图让 UnitOfWork 容忍每个会话的多个事务,我是否会失去/获得任何东西?我是否应该只检查一个打开的事务并在它已经提交时抛出一个异常,而不是创建一个新事务?

【问题讨论】:

  • 它是为 Web 应用程序设计的。

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


【解决方案1】:

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

是个好主意吗?视情况而定。

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

我想说,它在这些情况下效果很好:

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

UI 应用程序

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

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

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

简单的方法(tm)

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

我将整个交易处理简化到最低限度,以使其稳定且“防白痴”。我总是一起创建一个会话和一个事务,它要么提交要么不提交。

【讨论】:

  • 我的理解是ITransaction.Commit() 调用将刷新会话。使用同一个会话实例化一个新的ITransaction,并紧跟Commit(),什么情况下会生成一个StaleObjectException
  • 提交事务会释放锁。这使得它更有可能获得 StaleObjectExceptions。但是无论如何您都可以得到它们,因为当您在内存中更改数据时,数据库中的数据可能会发生变化。 NH 的乐观锁定至少可以检测到这些冲突。
  • 感谢您的详细回答。
【解决方案2】:

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

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

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

【讨论】:

  • 只是指出一些事情:1)已经有一个 System.Action ,所以这会让人感到困惑。 2)您的 Action 类没有定义交易的来源。 3) 这仍然会导致与 NHibernate 中的嵌套事务相同的错误(提交内部事务将使外部事务抛出 ObjectDisposedException)。
【解决方案3】:

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

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

【讨论】:

  • 这正是我们所做的,但在这种情况下它不起作用:我猜不能在评论中进行代码编辑......但如果你有另一个交易里面它不起作用.但它应该。嵌套事务在数据库中实现是有充分理由的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-10
  • 1970-01-01
  • 2020-12-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多