源码及系列文章目录
Git 源码 :https://github.com/tangsong1995/TS.Microservices
CSDN 资源 :https://download.csdn.net/download/qq_33649351/34675095
系列文章目录 :https://blog.csdn.net/qq_33649351/article/details/120998558
工作单元模式的特性
工作单元模式有以下几个特性:
- 使用同一上下文
- 跟踪实体的状态
- 保障事务一致性
实现工作单元模式
定义 IUnitOfWork 接口
public interface IUnitOfWork : IDisposable
{
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default);
}
IUnitOfWork 定义了两个接口:SaveChangesAsync 和 SaveEntitiesAsync。SaveChangesAsync 接口返回受影响行数,SaveEntitiesAsync 接口返回保存是否成功结果。
定义 ITransaction 事务管理接口
public interface ITransaction
{
IDbContextTransaction GetCurrentTransaction();
bool HasActiveTransaction { get; }
Task<IDbContextTransaction> BeginTransactionAsync(ICapPublisher capBus);
Task CommitTransactionAsync(IDbContextTransaction transaction);
void RollbackTransaction();
}
GetCurrentTransaction:获取当前事务
HasActiveTransaction :判断当前事务是否开启
BeginTransactionAsync:开启事务
CommitTransactionAsync:提交事务
RollbackTransaction:回滚事务
使用EF实现工作单元模式 EFContext
public class EFContext : DbContext, IUnitOfWork, ITransaction
{
protected IMediator _mediator;
public EFContext(DbContextOptions options, IMediator mediator) : base(options)
{
_mediator = mediator;
}
#region IUnitOfWork
public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default)
{
var result = await base.SaveChangesAsync(cancellationToken);
return true;
}
#endregion
#region ITransaction
private IDbContextTransaction _currentTransaction;
public IDbContextTransaction GetCurrentTransaction() => _currentTransaction;
public bool HasActiveTransaction => _currentTransaction != null;
public Task<IDbContextTransaction> BeginTransactionAsync(ICapPublisher capBus)
{
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
}
EFContext 继承了EF基类 DbContext ,并且实现了 IUnitOfWork, ITransaction 接口。
管理事务
定义 TransactionBehavior 管理事务:
public class TransactionBehavior<TDbContext, TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TDbContext : EFContext
{
ILogger _logger;
TDbContext _dbContext;
ICapPublisher _capBus;
public TransactionBehavior(TDbContext dbContext, ILogger logger, ICapPublisher capBus)
{
_dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_capBus = capBus ?? throw new ArgumentNullException(nameof(capBus));
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> 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(_capBus))
using (_logger.BeginScope("TransactionContext:{TransactionId}", transaction.TransactionId))
{
_logger.LogInformation("----- 开始事务 {TransactionId} ({@Command})", transaction.TransactionId, typeName, request);
response = await 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;
}
}
}