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
|
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;
|
return service;
|
||||||
}
|
}
|
||||||
public static IServiceCollection TryAddYiDbContext<DbContext>(this IServiceCollection service) where DbContext : class, ISqlSugarDbContext
|
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;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ namespace Yi.Framework.SqlSugarCore.Uow
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ISqlSugarDbContext GetDbContext()
|
public ISqlSugarDbContext GetDbContext()
|
||||||
{
|
{
|
||||||
|
|
||||||
return _sqlsugarDbContext;
|
return _sqlsugarDbContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CommitAsync(CancellationToken cancellationToken = default)
|
public async Task CommitAsync(CancellationToken cancellationToken = default)
|
||||||
|
|||||||
@@ -1,17 +1,11 @@
|
|||||||
using System;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
using SqlSugar;
|
||||||
using Volo.Abp.Data;
|
using Volo.Abp.Data;
|
||||||
using Volo.Abp.MultiTenancy;
|
using Volo.Abp.MultiTenancy;
|
||||||
using Volo.Abp.Threading;
|
using Volo.Abp.Threading;
|
||||||
using Volo.Abp.Uow;
|
using Volo.Abp.Uow;
|
||||||
using Volo.Abp;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using SqlSugar;
|
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
namespace Yi.Framework.SqlSugarCore.Uow
|
namespace Yi.Framework.SqlSugarCore.Uow
|
||||||
@@ -21,7 +15,9 @@ namespace Yi.Framework.SqlSugarCore.Uow
|
|||||||
private readonly ISqlSugarDbConnectionCreator _dbConnectionCreator;
|
private readonly ISqlSugarDbConnectionCreator _dbConnectionCreator;
|
||||||
private readonly string MasterTenantDbDefaultName = DbConnOptions.MasterTenantDbDefaultName;
|
private readonly string MasterTenantDbDefaultName = DbConnOptions.MasterTenantDbDefaultName;
|
||||||
public ILogger<UnitOfWorkSqlsugarDbContextProvider<TDbContext>> Logger { get; set; }
|
public ILogger<UnitOfWorkSqlsugarDbContextProvider<TDbContext>> Logger { get; set; }
|
||||||
|
public IServiceProvider ServiceProvider { get; set; }
|
||||||
|
|
||||||
|
private static AsyncLocalDbContextAccessor ContextInstance => AsyncLocalDbContextAccessor.Instance;
|
||||||
protected readonly IUnitOfWorkManager UnitOfWorkManager;
|
protected readonly IUnitOfWorkManager UnitOfWorkManager;
|
||||||
protected readonly IConnectionStringResolver ConnectionStringResolver;
|
protected readonly IConnectionStringResolver ConnectionStringResolver;
|
||||||
protected readonly ICancellationTokenProvider CancellationTokenProvider;
|
protected readonly ICancellationTokenProvider CancellationTokenProvider;
|
||||||
@@ -43,53 +39,74 @@ namespace Yi.Framework.SqlSugarCore.Uow
|
|||||||
_dbConnectionCreator = dbConnectionCreator;
|
_dbConnectionCreator = dbConnectionCreator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static object _databaseApiLock = new object();
|
||||||
public virtual async Task<TDbContext> GetDbContextAsync()
|
public virtual async Task<TDbContext> GetDbContextAsync()
|
||||||
{
|
{
|
||||||
|
|
||||||
var unitOfWork = UnitOfWorkManager.Current;
|
var unitOfWork = UnitOfWorkManager.Current;
|
||||||
if (unitOfWork == null)
|
if (unitOfWork == null|| unitOfWork.Options.IsTransactional==false)
|
||||||
{
|
{
|
||||||
UnitOfWorkManager.Begin(true);
|
if (ContextInstance.Current is null)
|
||||||
unitOfWork = UnitOfWorkManager.Current;
|
{
|
||||||
//取消工作单元强制性
|
ContextInstance.Current = (TDbContext)ServiceProvider.GetRequiredService<ISqlSugarDbContext>();
|
||||||
|
}
|
||||||
|
//提高体验,取消工作单元强制性
|
||||||
//throw new AbpException("A DbContext can only be created inside a unit of work!");
|
//throw new AbpException("A DbContext can only be created inside a unit of work!");
|
||||||
|
//如果不启用工作单元,创建一个新的db,不开启事务即可
|
||||||
|
return (TDbContext)ContextInstance.Current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var connectionStringName = ConnectionStrings.DefaultConnectionStringName;
|
var connectionStringName = ConnectionStrings.DefaultConnectionStringName;
|
||||||
|
|
||||||
|
//获取当前连接字符串,未多租户时,默认为空
|
||||||
var connectionString = await ResolveConnectionStringAsync(connectionStringName);
|
var connectionString = await ResolveConnectionStringAsync(connectionStringName);
|
||||||
// var dbContextKey = $"{this.GetType().FullName}_{connectionString}";
|
var dbContextKey = $"{this.GetType().FullName}_{connectionString}";
|
||||||
var dbContextKey = "Default";
|
|
||||||
var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey);
|
|
||||||
|
|
||||||
if (databaseApi == null)
|
|
||||||
|
lock (_databaseApiLock)
|
||||||
{
|
{
|
||||||
databaseApi = new SqlSugarDatabaseApi(
|
//尝试当前工作单元获取db
|
||||||
await CreateDbContextAsync(unitOfWork, connectionStringName, connectionString)
|
var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey);
|
||||||
);
|
|
||||||
unitOfWork.AddDatabaseApi(dbContextKey, databaseApi);
|
|
||||||
|
|
||||||
|
//当前没有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)
|
protected virtual async Task<TDbContext> CreateDbContextAsync(IUnitOfWork unitOfWork, string connectionStringName, string connectionString)
|
||||||
{
|
{
|
||||||
|
var creationContext = new SqlSugarDbContextCreationContext(connectionStringName, connectionString);
|
||||||
var dbContext = await CreateDbContextAsync(unitOfWork);
|
//将连接key进行传值
|
||||||
|
using (SqlSugarDbContextCreationContext.Use(creationContext))
|
||||||
//没有检测到使用多租户功能,默认使用默认库即可
|
|
||||||
if (string.IsNullOrWhiteSpace(connectionString))
|
|
||||||
{
|
{
|
||||||
connectionString = dbContext.Options.Url;
|
var dbContext = await CreateDbContextAsync(unitOfWork);
|
||||||
connectionStringName = DbConnOptions.TenantDbDefaultName;
|
|
||||||
|
//没有检测到使用多租户功能,默认使用默认库即可
|
||||||
|
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)
|
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)
|
protected virtual async Task<TDbContext> CreateDbContextAsync(IUnitOfWork unitOfWork)
|
||||||
{
|
{
|
||||||
return unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
|
return unitOfWork.Options.IsTransactional
|
||||||
//return unitOfWork.Options.IsTransactional
|
? await CreateDbContextWithTransactionAsync(unitOfWork)
|
||||||
// ? await CreateDbContextWithTransactionAsync(unitOfWork)
|
: unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
|
||||||
// : unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
|
|
||||||
}
|
}
|
||||||
protected virtual async Task<TDbContext> CreateDbContextWithTransactionAsync(IUnitOfWork unitOfWork)
|
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;
|
var activeTransaction = unitOfWork.FindTransactionApi(transactionApiKey) as SqlSugarTransactionApi;
|
||||||
//if (activeTransaction==null|| activeTransaction.Equals(default(SqlSugarTransactionApi)))
|
|
||||||
//{
|
|
||||||
|
|
||||||
var dbContext = unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
|
//该db还没有进行开启事务
|
||||||
var transaction = new SqlSugarTransactionApi(
|
if (activeTransaction == null)
|
||||||
dbContext
|
{
|
||||||
);
|
//获取到db添加事务即可
|
||||||
unitOfWork.AddTransactionApi(transactionApiKey, transaction);
|
var dbContext = unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
|
||||||
|
var transaction = new SqlSugarTransactionApi(
|
||||||
|
dbContext
|
||||||
|
);
|
||||||
|
unitOfWork.AddTransactionApi(transactionApiKey, transaction);
|
||||||
|
|
||||||
|
await dbContext.SqlSugarClient.Ado.BeginTranAsync();
|
||||||
//await Console.Out.WriteLineAsync("开始新的事务");
|
return dbContext;
|
||||||
// Console.WriteLine(dbContext.SqlSugarClient.ContextID);
|
}
|
||||||
await dbContext.SqlSugarClient.Ado.BeginTranAsync();
|
else
|
||||||
return dbContext;
|
{
|
||||||
//}
|
return (TDbContext)activeTransaction.GetDbContext();
|
||||||
//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();
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
using Volo.Abp.Application.Services;
|
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
|
namespace Yi.Abp.Application.Services
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 这是一个示例
|
||||||
|
/// </summary>
|
||||||
public class TestService : ApplicationService
|
public class TestService : ApplicationService
|
||||||
{
|
{
|
||||||
|
public ISqlSugarRepository<BannerEntity> sqlSugarRepository { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 你好世界
|
/// 你好世界,动态Api
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name"></param>
|
/// <param name="name"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
@@ -14,5 +20,34 @@ namespace Yi.Abp.Application.Services
|
|||||||
{
|
{
|
||||||
return name ?? "HelloWord";
|
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