简体   繁体   English

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

[英]can you have multiple transactions occur inside one session in nhibernate? And is it a bad idea?

I'm thinking about making my own IUnitOfWork implementation for an NHibernate persistence layer. 我正在考虑为NHibernate持久层创建自己的IUnitOfWork实现。

It seems that the right way to do this would be to have the ISession and the ITransaction instantiated in the constructor, and then disposed in the destructor or the Dispose() method. 似乎正确的方法是在构造函数中实例化ISessionITransaction ,然后在析构函数或Dispose()方法中进行Dispose()

Of course, if someone invokes the Save() method, then the ISession would be flushed and the ITransaction would be complete, so after calling Save() , there would not be a valid open transaction to Save() again... unless I committed the first transaction and immediately opened another, new transaction. 当然,如果有人调用Save()方法,那么ISession将被刷新并且ITransaction将完成,因此在调用Save() ,将再次没有有效的打开事务来Save() ...除非我提交了第一笔交易并立即开通了另一笔新交易。 But is this a good idea? 但这是个好主意吗?

Design-wise, it makes sense to do one commit operation, but I will not necessarily have control of the code and other developers may be less disciplined about following the UnitOfWork pattern. 在设计方面,做一个提交操作是有意义的,但我不一定能控制代码,而其他开发人员可能不太遵守UnitOfWork模式。

Do I lose/ gain anything by trying to make the UnitOfWork tolerant to multiple transactions per session? 通过尝试使UnitOfWork容忍每个会话的多个事务,我会失去/获得任何东西吗? Should I just check for an open transaction and throw an exception if it's already been committed, rather than making a new transaction? 我应该检查一个打开的事务,如果它已经被提交则抛出异常,而不是进行新的事务吗?

To answer the first question: yes it is possible to have multiple transactions in one session. 回答第一个问题:是的,可以在一个会话中拥有多个事务。

Is is a good idea? 是个好主意吗? It depends. 这取决于。

The problem is that changing data in the first transaction would be committed, while it is not sure if the whole unit of work (session) gets committed at the end. 问题是第一个事务中的数据更改将被提交,而不确定整个工作单元(会话)是否在最后提交。 When you get, let's say, a StaleObjectException in a later transaction, you already had some data committed. 当你得到一个稍后的事务中的StaleObjectException时,你已经提交了一些数据。 Note that this kind of exception makes your session unusable and you had to destroy it anyway. 请注意,这种异常使您的会话无法使用,无论如何您必须销毁它。 Then it is hard to start over and try again. 然后很难重新开始并再试一次。

I would say, it works well under these circumstances: 我想说,在这种情况下它运作良好:

  • It is a UI application 它是一个UI应用程序
  • Changes are only flushed in the last transaction. 更改仅在最后一个事务中刷新。

UI Application UI应用程序

Errors are handled by the user interactively. 错误由用户以交互方式处理。 This means that the user can see what's actually stored in a case of error and repeats the changes he made. 这意味着用户可以在错误的情况下查看实际存储的内容并重复他所做的更改。

Changes are only flushed in the last transaction 更改仅在最后一个事务中刷新

The session as implemented by NH only flushes changes at the end or "when necessary". 由NH实施的会话仅在最后或“必要时”刷新更改。 So it would be possible to keep changes in memory until the session gets committed. 因此,在会话提交之前,可以保留内存中的更改。 The problem is that NH needs to flush the session before every query, which is hard to control. 问题是NH需要在每次查询之前刷新会话,这很难控制。 It can be turned off, which leads to side effects. 它可以关闭,这会导致副作用。 When writing simple transactions, you may have it under control. 在编写简单的事务时,您可以控制它。 In a complex system it's virtually impossible to make sure that nothing is going wrong. 在复杂的系统中,几乎不可能确保没有任何问题。

The Simple Way (tm) 简单方法(tm)

I wrote the persistence layer of a quite large client-server system. 我编写了一个非常大的客户端 - 服务器系统的持久层。 In such a system, you don't have a user handling errors directly. 在这样的系统中,您没有用户直接处理错误。 You need to handle the errors in the system and return control to the client in a consistent state. 您需要处理系统中的错误并以一致的状态将控制权返回给客户端。

I simplified the whole transaction handling to an absolute minimum, in order to make it stable and "idiot proof". 我将整个事务处理简化为绝对最小化,以使其稳定并且“白痴证明”。 I have always a session and a transaction created together and it gets either committed or not. 我总是创建一个会话和一个事务,它会被提交或不提交。

There are multiple option available to implement nhibernate nested transaction with unit of work. 有多个选项可用于实现具有工作单元的nhibernate嵌套事务。

Here I am using Command pattern for unit of work. 在这里,我使用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();
    }
}

I think that the solution with one transaction per unit of work is too restrictive. 我认为每单位工作一次交易的解决方案限制性太强。 In some environments one can need the ability to perform several transactions per session. 在某些环境中,人们可能需要能够在每个会话中执行多个事务。 I myself manage the transactions explicitly and it seems to be a flexible solution. 我自己明确地管理交易,它似乎是一个灵活的解决方案。

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

The usage looks like this. 用法如下所示。 It is easily incorporated into any pattern. 它很容易融入任何模式。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM