博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.NET Core开发实战(第28课:工作单元模式(UnitOfWork):管理好你的事务)--学习笔记...
阅读量:4031 次
发布时间:2019-05-24

本文共 5858 字,大约阅读时间需要 19 分钟。

28 | 工作单元模式(UnitOfWork):管理好你的事务

工作单元模式有如下几个特性:

1、使用同一上下文

2、跟踪实体的状态

3、保障事务一致性

我们对实体的操作,最终的状态都是应该如实保存到我们的存储中,进行持久化

接下来看一下代码

为了实现工作单元模式,这里定义了一个工作单元的接口

public interface IUnitOfWork : IDisposable{    Task
SaveChangesAsync(CancellationToken cancellationToken = default); Task
SaveEntitiesAsync(CancellationToken cancellationToken = default);}

这两个方法的区别是:一个是返回的 int 是指我们影响的数据条数,另外一个返回 bool 表示我们保存是否成功,本质上这两个方法达到的效果是相同的

另外还定义了一个事务管理的接口

public interface ITransaction{    // 获取当前事务    IDbContextTransaction GetCurrentTransaction();    // 判断当前事务是否开启    bool HasActiveTransaction { get; }    // 开启事务    Task
BeginTransactionAsync(); // 提交事务 Task CommitTransactionAsync(IDbContextTransaction transaction); // 事务回滚 void RollbackTransaction();}

在实现上我们是借助 EF 来实现工作单元模式的

看一下 EFContext 的定义

/// /// DbContext 是 EF 的基类,然后实现了 UnitOfWork 的接口和事务的接口/// public class EFContext : DbContext, IUnitOfWork, ITransaction{    protected IMediator _mediator;    ICapPublisher _capBus;    // 后面的章节会详细讲到这两个参数    public EFContext(DbContextOptions options, IMediator mediator, ICapPublisher capBus) : base(options)    {        _mediator = mediator;        _capBus = capBus;    }    #region IUnitOfWork    public async Task
SaveEntitiesAsync(CancellationToken cancellationToken = default) { var result = await base.SaveChangesAsync(cancellationToken); //await _mediator.DispatchDomainEventsAsync(this); return true; } 可以看到这个方法实际上与上面的方法是相同的,所以这个方法可以不实现 //public override Task
SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default) //{ // return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); //} #endregion #region ITransaction private IDbContextTransaction _currentTransaction;// 把当前的事务用一个字段存储 public IDbContextTransaction GetCurrentTransaction() => _currentTransaction;// 获取当前的事务就是返回存储的私有对象 public bool HasActiveTransaction => _currentTransaction != null;// 事务是否开启是判断当前这个事务是否为空 ///
/// 开启事务 /// ///
public Task
BeginTransactionAsync() { if (_currentTransaction != null) return null; _currentTransaction = Database.BeginTransaction(_capBus, autoCommit: false); return Task.FromResult(_currentTransaction); } ///
/// 提交事务 /// ///
当前事务 ///
public async Task CommitTransactionAsync(IDbContextTransaction transaction) { if (transaction == null) throw new ArgumentNullException(nameof(transaction)); if (transaction != _currentTransaction) throw new InvalidOperationException($"Transaction {transaction.TransactionId} is not current"); try { await SaveChangesAsync();// 将当前所有的变更都保存到数据库 transaction.Commit(); } catch { RollbackTransaction(); throw; } finally { if (_currentTransaction != null) { // 最终需要把当前事务进行释放,并且置为空 // 这样就可以多次的开启事务和提交事务 _currentTransaction.Dispose(); _currentTransaction = null; } } } ///
/// 回滚 /// public void RollbackTransaction() { try { _currentTransaction?.Rollback(); } finally { if (_currentTransaction != null) { _currentTransaction.Dispose(); _currentTransaction = null; } } } #endregion}

另外一个我们还是需要关注的一点就是如何管理我们的事务

这里有一个类 TransactionBehavior,这个类是用来注入我们的事务的管理过程的,具体它是怎么工作的在后续的章节会讲到,这里先关注它的实现过程

public class TransactionBehavior
: IPipelineBehavior
where TDbContext : EFContext{ ILogger _logger; TDbContext _dbContext; ICapPublisher _capBus; public TransactionBehavior(TDbContext dbContext, ICapPublisher capBus, ILogger logger) { _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); _capBus = capBus ?? throw new ArgumentNullException(nameof(capBus)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public async Task
Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate
next) { var response = default(TResponse); var typeName = request.GetGenericTypeName(); try { // 首先判断当前是否有开启事务 if (_dbContext.HasActiveTransaction) { return await next(); } // 定义了一个数据库操作执行的策略,比如说可以在里面嵌入一些重试的逻辑,这里创建了一个默认的策略 var strategy = _dbContext.Database.CreateExecutionStrategy(); await strategy.ExecuteAsync(async () => { Guid transactionId; using (var transaction = await _dbContext.BeginTransactionAsync()) using (_logger.BeginScope("TransactionContext:{TransactionId}", transaction.TransactionId)) { _logger.LogInformation("----- 开始事务 {TransactionId} ({@Command})", transaction.TransactionId, typeName, request); response = await next();// next 实际上是指我们的后续操作,这里的模式有点像之前讲的中间件模式 _logger.LogInformation("----- 提交事务 {TransactionId} {CommandName}", transaction.TransactionId, typeName); await _dbContext.CommitTransactionAsync(transaction); transactionId = transaction.TransactionId; } }); return response; } catch (Exception ex) { _logger.LogError(ex, "处理事务出错 {CommandName} ({@Command})", typeName, request); throw; } }}

回过头来看一下我们的 EFContext,EFContext 实现 IUnitOfWork,工作单元模式的核心,它实现了事务的管理和工作单元模式,我们就可以借助 EFContext 来实现我们的仓储层

转载地址:http://kiwdi.baihongyu.com/

你可能感兴趣的文章
AsyncTask、View.post(Runnable)、ViewTreeObserver三种方式总结frame animation自动启动
查看>>
Android中AsyncTask的简单用法
查看>>
S3C6410启动模式介绍
查看>>
2440初始化存储器原理(接上一篇)
查看>>
S3C2440 USB 设备控制器(转)
查看>>
Linux usb 设备驱动 (1)
查看>>
解决跨网场景下,CAS重定向无法登录的问题(无需修改现有代码)
查看>>
java反编译命令
查看>>
activemq依赖包获取
查看>>
概念区别
查看>>
关于静态块、静态属性、构造块、构造方法的执行顺序
查看>>
final 的作用
查看>>
在Idea中使用Eclipse编译器
查看>>
idea讲web项目部署到tomcat,热部署
查看>>
优化IDEA启动速度,快了好多。后面有什么优化点,会继续往里面添加
查看>>
JMeter 保持sessionId
查看>>
IDEA Properties中文unicode转码问题
查看>>
Idea下安装Lombok插件
查看>>
zookeeper
查看>>
Idea导入的工程看不到src等代码
查看>>