refactor: 魔改工作单元体系
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ namespace Yi.Framework.SqlSugarCore.Uow
|
||||
}
|
||||
|
||||
public ISqlSugarDbContext GetDbContext()
|
||||
{
|
||||
|
||||
return _sqlsugarDbContext;
|
||||
{
|
||||
|
||||
return _sqlsugarDbContext;
|
||||
}
|
||||
|
||||
public async Task CommitAsync(CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user