refactor: 魔改工作单元体系

This commit is contained in:
橙子
2024-01-25 01:43:00 +08:00
parent e614935693
commit 6b96231087
6 changed files with 165 additions and 68 deletions

View File

@@ -0,0 +1,19 @@
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.SqlSugarCore
{
public class AsyncLocalDbContextAccessor
{
public static AsyncLocalDbContextAccessor Instance { get; } = new();
public ISqlSugarDbContext? Current
{
get => _currentScope.Value;
set => _currentScope.Value = value;
}
public AsyncLocalDbContextAccessor()
{
_currentScope = new AsyncLocal<ISqlSugarDbContext?>();
}
private readonly AsyncLocal<ISqlSugarDbContext> _currentScope;
}
}

View File

@@ -0,0 +1,29 @@
using System.Data.Common;
using Volo.Abp;
namespace Yi.Framework.SqlSugarCore;
public class SqlSugarDbContextCreationContext
{
public static SqlSugarDbContextCreationContext Current => _current.Value;
private static readonly AsyncLocal<SqlSugarDbContextCreationContext> _current = new AsyncLocal<SqlSugarDbContextCreationContext>();
public string ConnectionStringName { get; }
public string ConnectionString { get; }
public DbConnection ExistingConnection { get; internal set; }
public SqlSugarDbContextCreationContext(string connectionStringName, string connectionString)
{
ConnectionStringName = connectionStringName;
ConnectionString = connectionString;
}
public static IDisposable Use(SqlSugarDbContextCreationContext context)
{
var previousValue = Current;
_current.Value = context;
return new DisposeAction(() => _current.Value = previousValue);
}
}

View File

@@ -13,12 +13,12 @@ namespace Yi.Framework.SqlSugarCore
{
public static IServiceCollection AddYiDbContext<DbContext>(this IServiceCollection service) where DbContext : class, ISqlSugarDbContext
{
service.Replace(new ServiceDescriptor(typeof(ISqlSugarDbContext), typeof(DbContext), ServiceLifetime.Scoped));
service.Replace(new ServiceDescriptor(typeof(ISqlSugarDbContext), typeof(DbContext), ServiceLifetime.Transient));
return service;
}
public static IServiceCollection TryAddYiDbContext<DbContext>(this IServiceCollection service) where DbContext : class, ISqlSugarDbContext
{
service.TryAdd(new ServiceDescriptor(typeof(ISqlSugarDbContext), typeof(DbContext), ServiceLifetime.Scoped));
service.TryAdd(new ServiceDescriptor(typeof(ISqlSugarDbContext), typeof(DbContext), ServiceLifetime.Transient));
return service;
}

View File

@@ -13,9 +13,9 @@ namespace Yi.Framework.SqlSugarCore.Uow
}
public ISqlSugarDbContext GetDbContext()
{
return _sqlsugarDbContext;
{
return _sqlsugarDbContext;
}
public async Task CommitAsync(CancellationToken cancellationToken = default)

View File

@@ -1,17 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using SqlSugar;
using Volo.Abp.Data;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
using Volo.Abp.Uow;
using Volo.Abp;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.SqlSugarCore.Uow
@@ -21,7 +15,9 @@ namespace Yi.Framework.SqlSugarCore.Uow
private readonly ISqlSugarDbConnectionCreator _dbConnectionCreator;
private readonly string MasterTenantDbDefaultName = DbConnOptions.MasterTenantDbDefaultName;
public ILogger<UnitOfWorkSqlsugarDbContextProvider<TDbContext>> Logger { get; set; }
public IServiceProvider ServiceProvider { get; set; }
private static AsyncLocalDbContextAccessor ContextInstance => AsyncLocalDbContextAccessor.Instance;
protected readonly IUnitOfWorkManager UnitOfWorkManager;
protected readonly IConnectionStringResolver ConnectionStringResolver;
protected readonly ICancellationTokenProvider CancellationTokenProvider;
@@ -43,53 +39,74 @@ namespace Yi.Framework.SqlSugarCore.Uow
_dbConnectionCreator = dbConnectionCreator;
}
private static object _databaseApiLock = new object();
public virtual async Task<TDbContext> GetDbContextAsync()
{
var unitOfWork = UnitOfWorkManager.Current;
if (unitOfWork == null)
if (unitOfWork == null|| unitOfWork.Options.IsTransactional==false)
{
UnitOfWorkManager.Begin(true);
unitOfWork = UnitOfWorkManager.Current;
//取消工作单元强制性
if (ContextInstance.Current is null)
{
ContextInstance.Current = (TDbContext)ServiceProvider.GetRequiredService<ISqlSugarDbContext>();
}
//提高体验,取消工作单元强制性
//throw new AbpException("A DbContext can only be created inside a unit of work!");
//如果不启用工作单元创建一个新的db不开启事务即可
return (TDbContext)ContextInstance.Current;
}
var connectionStringName = ConnectionStrings.DefaultConnectionStringName;
//获取当前连接字符串,未多租户时,默认为空
var connectionString = await ResolveConnectionStringAsync(connectionStringName);
// var dbContextKey = $"{this.GetType().FullName}_{connectionString}";
var dbContextKey = "Default";
var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey);
var dbContextKey = $"{this.GetType().FullName}_{connectionString}";
if (databaseApi == null)
lock (_databaseApiLock)
{
databaseApi = new SqlSugarDatabaseApi(
await CreateDbContextAsync(unitOfWork, connectionStringName, connectionString)
);
unitOfWork.AddDatabaseApi(dbContextKey, databaseApi);
//尝试当前工作单元获取db
var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey);
//当前没有db创建一个新的db
if (databaseApi == null)
{
//db根据连接字符串来创建
databaseApi = new SqlSugarDatabaseApi(
CreateDbContextAsync(unitOfWork, connectionStringName, connectionString).Result
);
//创建的db加入到当前工作单元中
unitOfWork.AddDatabaseApi(dbContextKey, databaseApi);
}
return (TDbContext)((SqlSugarDatabaseApi)databaseApi).DbContext;
}
return (TDbContext)((SqlSugarDatabaseApi)databaseApi).DbContext; ;
}
protected virtual async Task<TDbContext> CreateDbContextAsync(IUnitOfWork unitOfWork, string connectionStringName, string connectionString)
{
var dbContext = await CreateDbContextAsync(unitOfWork);
//没有检测到使用多租户功能,默认使用默认库即可
if (string.IsNullOrWhiteSpace(connectionString))
var creationContext = new SqlSugarDbContextCreationContext(connectionStringName, connectionString);
//将连接key进行传值
using (SqlSugarDbContextCreationContext.Use(creationContext))
{
connectionString = dbContext.Options.Url;
connectionStringName = DbConnOptions.TenantDbDefaultName;
var dbContext = await CreateDbContextAsync(unitOfWork);
//没有检测到使用多租户功能,默认使用默认库即可
if (string.IsNullOrWhiteSpace(connectionString))
{
connectionString = dbContext.Options.Url;
connectionStringName = DbConnOptions.TenantDbDefaultName;
}
//获取到DB之后对多租户多库进行处理
var changedDbContext = DatabaseChange(dbContext, connectionStringName, connectionString);
return changedDbContext;
}
//获取到DB之后对多租户多库进行处理
var changedDbContext = DatabaseChange(dbContext, connectionStringName, connectionString);
return changedDbContext;
}
protected virtual TDbContext DatabaseChange(TDbContext dbContext, string configId, string connectionString)
@@ -138,38 +155,35 @@ namespace Yi.Framework.SqlSugarCore.Uow
protected virtual async Task<TDbContext> CreateDbContextAsync(IUnitOfWork unitOfWork)
{
return unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
//return unitOfWork.Options.IsTransactional
// ? await CreateDbContextWithTransactionAsync(unitOfWork)
// : unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
return unitOfWork.Options.IsTransactional
? await CreateDbContextWithTransactionAsync(unitOfWork)
: unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
}
protected virtual async Task<TDbContext> CreateDbContextWithTransactionAsync(IUnitOfWork unitOfWork)
{
var transactionApiKey = $"Sqlsugar_Default" + Guid.NewGuid().ToString();
//事务key
var transactionApiKey = $"SqlsugarCore_{SqlSugarDbContextCreationContext.Current.ConnectionString}";
//尝试查找事务
var activeTransaction = unitOfWork.FindTransactionApi(transactionApiKey) as SqlSugarTransactionApi;
//if (activeTransaction==null|| activeTransaction.Equals(default(SqlSugarTransactionApi)))
//{
var dbContext = unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
var transaction = new SqlSugarTransactionApi(
dbContext
);
unitOfWork.AddTransactionApi(transactionApiKey, transaction);
//该db还没有进行开启事务
if (activeTransaction == null)
{
//获取到db添加事务即可
var dbContext = unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
var transaction = new SqlSugarTransactionApi(
dbContext
);
unitOfWork.AddTransactionApi(transactionApiKey, transaction);
//await Console.Out.WriteLineAsync("开始新的事务");
// Console.WriteLine(dbContext.SqlSugarClient.ContextID);
await dbContext.SqlSugarClient.Ado.BeginTranAsync();
return dbContext;
//}
//else
//{
// var db= activeTransaction.GetDbContext().SqlSugarClient;
// // await Console.Out.WriteLineAsync("继续老的事务");
// // Console.WriteLine(activeTransaction.DbContext.SqlSugarClient);
// await activeTransaction.GetDbContext().SqlSugarClient.Ado.BeginTranAsync();
// return (TDbContext)activeTransaction.GetDbContext();
//}
await dbContext.SqlSugarClient.Ado.BeginTranAsync();
return dbContext;
}
else
{
return (TDbContext)activeTransaction.GetDbContext();
}
}

View File

@@ -1,12 +1,18 @@
using Volo.Abp.Application.Services;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
using Yi.Framework.Bbs.Domain.Entities.Forum;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Abp.Application.Services
{
/// <summary>
/// 这是一个示例
/// </summary>
public class TestService : ApplicationService
{
public ISqlSugarRepository<BannerEntity> sqlSugarRepository { get; set; }
/// <summary>
/// 你好世界
/// 你好世界动态Api
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
@@ -14,5 +20,34 @@ namespace Yi.Abp.Application.Services
{
return name ?? "HelloWord";
}
/// <summary>
/// 工作单元魔改
/// 用户体验优先,万金油模式,支持多线程并发安全,支持多线程工作单元,支持无工作单元,支持。。。
/// 自动在各个情况处理db客户端最优解之一
/// </summary>
/// <returns></returns>
public async Task GetUowAsync()
{
int i = 10;
List<Task> tasks = new List<Task>();
while (i > 0)
{
tasks.Add(Task.Run(async () =>
{
using (var uow = UnitOfWorkManager.Begin(true, true))
{
await sqlSugarRepository.InsertAsync(new BannerEntity { Name = "插入1" });
await uow.CompleteAsync();
}
await sqlSugarRepository.InsertAsync(new BannerEntity { Name = "插入2" });
}));
await sqlSugarRepository.InsertAsync(new BannerEntity { Name = "插入3" });
i--;
}
await Task.WhenAll(tasks);
}
}
}