事务管理其实是应用服务层干的事。事务的协调管理都是由工作单元来负责的
所以,我们千万不能因为工作单元和仓储有联系就将它放置在领域层里面:事务的提供往往是由数据库管理程序来提供的,而这一类组件我们一般将它们放置在基础构架层,而领域层可以依赖于基础构架层,所以千万要注意,保持您的领域层足够干净,不要让其它的东西干扰它,也更不要将事务处理这类东西放到了您的领域层来。
公共连接和事务管理方法
第一种方法:当Web请求开始的时候创建一个连接,在所有的数据库操作时使用相同的连接,并且在请求结束时关闭或者释放该连接。这种方法很简单但是不够高效。
- 在一个请求中也许没有数据库操作,但是连接已经打开了。这造成了连接池的无效使用。
- 在一次请求中,可能请求需要消耗很长的时间而数据库操作只花费很短的时间,这也会造成连接池的无效使用。
- 这只在Web应用中是可行的。如果应用是一个Windows服务,那么可能不会实现。
以事务的方式执行数据库操作已被认为是一种最佳实践。如果一个操作失败了,那么所有的操作都会回滚。因为一个事务可以锁定数据库中的一些行(甚至表),所以它必须是短暂存活的。
第二种方法:当需要时(仅在使用前)创建一个连接,使用后立即关闭。这是最有效的,但是到处创建或者释放连接是一项重复乏味的工作。
ABP的约定
以下方法类型被认为是一个工作单元:
- ASP.NET Core MVC Controller Actions.
- ASP.NET Core Razor Page Handlers.
- 应用程序 方法.
- 仓储方法.
这边主要关心的是:某些情况下,我们需要创建一个新的工作单元作用域。
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace AbpDemo
{
public class MyService : ITransientDependency
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
public MyService(IUnitOfWorkManager unitOfWorkManager)
{
_unitOfWorkManager = unitOfWorkManager;
}
public virtual async Task FooAsync()
{
// 傻逼看这里
using (var uow = _unitOfWorkManager.Begin(
requiresNew: true, isTransactional: false
))
{
//...
await uow.CompleteAsync();
}
}
}
}
Begin
方法有以下可选参数:
requiresNew
(bool
): 设置为true
可忽略周围的工作单元,并使用提供的选项启动新的UOW. 默认值为false
. 如果为false
,并且周围有UOW,则Begin
方法实际上不会开始新的UOW,而是以静默方式参与现有的UOW.isTransactional
(bool
). 默认为false
.isolationLevel
(IsolationLevel?
): 如果UOW是事务的,用于设置数据库事务的隔离级别. 如果未设置,则使用默认值.TimeOut
(int?
): 用于设置UOW的超时值. **默认值为null
**并回退到默认配置值.
一般来说,不需要关心这些参数,只需要new 一个新的工作单元域就好了:
using (var uow = _unitOfWorkManager.Begin(new AbpUnitOfWorkOptions(), true)))