在nhibernate中,您可以在一个会话中发生多个事务吗?这是个坏主意吗

本文关键字:事务 一个 nhibernate 会话 | 更新日期: 2023-09-27 18:28:32

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

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

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

从设计角度来看,做一个提交操作是有意义的,但我不一定能控制代码,其他开发人员可能不太遵守UnitOfWork模式。

通过尝试使UnitOfWork能够容忍每个会话的多个事务,我会失去/获得什么吗?我应该只检查一个打开的事务并在它已经提交的情况下抛出异常,而不是创建一个新的事务吗?

在nhibernate中,您可以在一个会话中发生多个事务吗?这是个坏主意吗

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

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

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

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

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

UI应用程序

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

更改仅在最后一笔交易中刷新

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

简单方法(tm)

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

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

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

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

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

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

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