NHibernate:我应该在什么范围使用事务? [英] NHibernate: At what scope I should use transaction?

查看:61
本文介绍了NHibernate:我应该在什么范围使用事务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用NHibernate开发数据访问层.它将在我的业务逻辑层中使用.我的应用程序是多个其他应用程序(ASP.NET MVC,Windows服务,Windows窗体,ASP.NET Web API)的集合,它们都将使用相同的业务逻辑层.业务逻辑层将访问数据访问层.应用程序不会直接访问数据访问层.

I am developing Data Access Layer using NHibernate. It will be used in my Business Logic Layer. My application is collection of multiple other applications (ASP.NET MVC, Windows Services, Windows Forms, ASP.NET Web API) those all will use same Business Logic Layer. Business Logic Layer will access Data Access Layer. Applications will NOT access Data Access Layer directly.

我知道我不应该依赖隐式事务,而应该在显式事务中包括所有数据库调用(包括READ调用).

I am aware that I should NOT depend on implicit transaction and should include all database calls (including READ calls) in explicit transaction.

据我了解,交易必须是短暂的.如果寿命长,可能会造成问题.请参考 1

In my understanding, transaction must be short lived. If it lives for long, it may create issues. Refer 1 and 2.

许多资源(在StackOverflow和其他站点上)建议将事务代码包含在using块中.这确实很有意义,因为它有助于为每个数据库调用使用显式事务.这也有助于缩短交易时间.这种方法的问题在于,批处理仅限于using块. UnitOfWork没有得到充分利用.

Many resources (on StackOverflow and other sites) suggest enclosing transaction code in using block. This really makes sense because it helps using explicit transaction for each database call. It also help making transaction short lived. Problem with this approach is that, batching is limited to using block only. UnitOfWork is not fully utilized.

另一方面,许多资源(在StackOverflow和其他站点上)建议在更高级别上使用事务,例如Web应用程序中的web-request(每个请求的会话数)或WinForms中的每窗口形式"等.这可以改善查询的批处理并帮助更好地利用UnitOfWork模式.这种方法的问题在于,交易是长期存在的.

On other hand, many resources (on StackOverflow and other sites) suggest using transaction on some higher level like web-request (session per request) in web application OR "per windows form" in WinForms etc. This improves batching of queries and help taking better advantage of UnitOfWork pattern. Problem with this approach is that, transactions are long lived.

方法1]将事务公开给应用程序,并对其进行处理.

选项1-:主叫方可以在请求级别进行处理.这种方法的缺点是,交易可能存在很长一段时间.

Option 1 - Caller can handle this at request level. Drawback of this approach is that, transactions may be long lived.

选项2-如果他不这样做,则唯一的方法是在较低级别上处理它,例如每个方法"或每个小代码块".但是现在,他必须确保自己开始事务并正确提交/回滚它.这降低了可读性,在出现问题的情况下很难进行代码审查和调试.另外,如果无论如何必须将其置于较低级别,为什么不将其包含在业务逻辑层中呢?

Option 2 - If he does not do so, the only way is to handle it at lower level like "per method" or "per small block of code". But now, he has to make sure he begins the transaction and commit/rollback it properly. This reduces readability, is difficult to code-review and debug in case of problem. Also, if this has to be at lower level anyway, why not include this in Business Logic Layer instead?

方法2]在业务逻辑层内控制事务.

这使得所有交易都是短暂的.但这并没有充分利用批处理或UnitOfWork的优势. BLL可能事先不知道如何通过调用应用程序来进行数据库调用.

This makes all transactions short lived. But this does not take good advantage of batching or UnitOfWork. BLL may not know in advance how database calls will be made by calling application.

BeginCommit交易的推荐位置是什么,这将充分利用批处理和兑现UnitOfWork的优势?

What is recommended location to Begin and Commit transaction which will take good advantage of batching and honoring UnitOfWork?

我刚刚发现了很棒的文章UnitOfWork上.以下是从中提取的一些内容:

I just found excellent article on UnitOfWork. Following are some of the extracts from the same:

不要使用每次操作会话"反模式:不要在单个线程中为每个简单的数据库调用打开和关闭Session.数据库事务也是如此.应用程序中的数据库调用是按计划的顺序进行的.它们被分组为原子工作单元.这也意味着在每条SQL语句之后自动提交在应用程序中都是无用的,因为此模式用于临时SQL控制台工作.

Do not use the session-per-operation antipattern: do not open and close a Session for every simple database call in a single thread. The same is true for database transactions. Database calls in an application are made using a planned sequence; they are grouped into atomic units of work. This also means that auto-commit after every single SQL statement is useless in an application as this mode is intended for ad-hoc SQL console work.

数据库事务绝不是可选的.与数据库的所有通信都必须在事务内部进行.应该避免读取数据的自动提交行为,因为许多小型事务的执行效果不佳于一个明确定义的工作单元.后者也更易于维护和扩展.

Database transactions are never optional. All communication with a database has to occur inside a transaction. Auto-commit behavior for reading data should be avoided, as many small transactions are unlikely to perform better than one clearly defined unit of work. The latter is also more maintainable and extensible.

在多用户客户端/服务器应用程序中,最常见的模式是每次请求会话.在此模型中,来自客户端的请求被发送到服务器,在服务器上运行Hibernate持久层.将打开一个新的Hibernate Session,并在此工作单元中执行所有数据库操作.工作完成后,一旦准备好客户端的响应,便会刷新并关闭会话.使用单个数据库事务处理服务于客户的请求,在打开和关闭会话时启动并提交该请求.两者之间是一对一的关系,该模型非常适合许多应用.

The most common pattern in a multi-user client/server application is session-per-request. In this model, a request from the client is sent to the server, where the Hibernate persistence layer runs. A new Hibernate Session is opened, and all database operations are executed in this unit of work. On completion of the work, and once the response for the client has been prepared, the session is flushed and closed. Use a single database transaction to serve the clients request, starting and committing it when you open and close the Session. The relationship between the two is one-to-one and this model is a perfect fit for many applications.

每个请求会话模式不是设计工作单元的唯一方法.许多业务流程需要与用户进行一系列与数据库访问交错的交互.在Web和企业应用程序中,数据库事务跨越用户交互是不可接受的.

The session-per-request pattern is not the only way of designing units of work. Many business processes require a whole series of interactions with the user that are interleaved with database accesses. In web and enterprise applications, it is not acceptable for a database transaction to span a user interaction.

数据库或系统事务边界始终是必需的.在数据库事务之外无法与数据库进行任何通信(这似乎使许多习惯自动提交模式的开发人员感到困惑).始终使用明确的事务边界,即使是只读操作也是如此.根据您的隔离级别和数据库功能,这可能不是必需的,但是如果您始终明确地划分事务,则没有不利之处.当然,即使读取数据,单个数据库事务的性能也将比许多小型事务更好.

Database, or system, transaction boundaries are always necessary. No communication with the database can occur outside of a database transaction (this seems to confuse many developers who are used to the auto-commit mode). Always use clear transaction boundaries, even for read-only operations. Depending on your isolation level and database capabilities this might not be required, but there is no downside if you always demarcate transactions explicitly. Certainly, a single database transaction is going to perform better than many small transactions, even for reading data.

推荐答案

为什么不让服务知道交易?

Why not make the service(s) transaction aware?

类似

    protected virtual TResult Transact<TResult>(Func<TResult> func)
    {
        if (_session.Transaction.IsActive)
            return func.Invoke();

        TResult result;
        using (var tx = _session.BeginTransaction(IsolationLevel.ReadCommitted))
        {
            result = func.Invoke();
            tx.Commit();
        }

        return result;
    }

    protected virtual void Transact(System.Action action)
    {
        Transact(() =>
        {
            action.Invoke();
            return false;
        });
    }

您的服务或仓库中的

,用于检查某笔交易是否有效,是否参与了一笔有效交易,如果不存在,则创建一个新交易.

in your service or repo that checks if a transaction is active and participates in an active one or creates a new transaction if non exists.

现在,您可以在一个事务处理下将多个服务调用组合在一起,而不必孤立地进行每个调用.

Now you can compose multiple service calls together under one transcation instead of having each call in isolation.

这篇关于NHibernate:我应该在什么范围使用事务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆