添加启动时未分表dbcontext检查,添加动态读写分离库支持,发布x.3.1.66

This commit is contained in:
xuejiaming 2021-12-04 00:10:07 +08:00
parent 48deab923f
commit da4675d549
21 changed files with 571 additions and 297 deletions

View File

@ -13,8 +13,10 @@ using ShardingCore;
using ShardingCore.Bootstrapers;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
using ShardingCore.Core.VirtualDatabase.VirtualTables;
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RouteRuleEngine;
using ShardingCore.Core.VirtualRoutes.TableRoutes;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine;
using ShardingCore.Core.VirtualTables;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
@ -37,6 +39,8 @@ namespace ShardingCore6x
private readonly IStreamMergeContextFactory<DefaultShardingDbContext> _streamMergeContextFactory;
private readonly ActualConnectionStringManager<DefaultShardingDbContext> _actualConnectionStringManager;
private readonly IVirtualDataSource<DefaultShardingDbContext> _virtualDataSource;
private readonly IDataSourceRouteRuleEngineFactory<DefaultShardingDbContext> _dataSourceRouteRuleEngineFactory;
private readonly ITableRouteRuleEngineFactory<DefaultShardingDbContext> _tableRouteRuleEngineFactory;
public EFCoreCrud()
{
var services = new ServiceCollection();
@ -119,6 +123,8 @@ namespace ShardingCore6x
ShardingContainer.GetService<IStreamMergeContextFactory<DefaultShardingDbContext>>();
_actualConnectionStringManager = new ActualConnectionStringManager<DefaultShardingDbContext>();
_virtualDataSource = ShardingContainer.GetService<IVirtualDataSource<DefaultShardingDbContext>>();
_dataSourceRouteRuleEngineFactory = ShardingContainer.GetService<IDataSourceRouteRuleEngineFactory<DefaultShardingDbContext>>();
_tableRouteRuleEngineFactory = ShardingContainer.GetService<ITableRouteRuleEngineFactory<DefaultShardingDbContext>>();
}
@ -146,16 +152,45 @@ namespace ShardingCore6x
// var connectionString = _actualConnectionStringManager.GetConnectionString("ds0", false);
// }
//}
//[Benchmark]
//public async Task ShardingCreateStreamMergeContext()
//{
// for (int i = 0; i < N; i++)
// {
// var next = new Random().Next(1000000, 3000000).ToString();
// var queryable = _defaultShardingDbContext.Set<Order>().Where(o => o.Id == next);
// var firstOrDefaultAsync = _streamMergeContextFactory.Create(queryable, _defaultShardingDbContext);
// }
//}
[Benchmark]
public async Task CreateQueryable()
{
for (int i = 0; i < N; i++)
{
var next = new Random().Next(1000000, 3000000).ToString();
var queryable = _defaultShardingDbContext.Set<Order>().Where(o => o.Id == next);
}
}
[Benchmark]
public async Task DataSourceRouteRuleEngineFactory()
{
for (int i = 0; i < N; i++)
{
var next = new Random().Next(1000000, 3000000).ToString();
var queryable = _defaultShardingDbContext.Set<Order>().Where(o => o.Id == next);
_dataSourceRouteRuleEngineFactory.Route(queryable);
}
}
[Benchmark]
public async Task TableRouteRuleEngineFactory()
{
for (int i = 0; i < N; i++)
{
var next = new Random().Next(1000000, 3000000).ToString();
var queryable = _defaultShardingDbContext.Set<Order>().Where(o => o.Id == next);
_tableRouteRuleEngineFactory.Route(queryable);
}
}
[Benchmark]
public async Task ShardingCreateStreamMergeContext()
{
for (int i = 0; i < N; i++)
{
var next = new Random().Next(1000000, 3000000).ToString();
var queryable = _defaultShardingDbContext.Set<Order>().Where(o => o.Id == next);
var firstOrDefaultAsync = _streamMergeContextFactory.Create(queryable, _defaultShardingDbContext);
}
}
//[Benchmark]
//public async Task NoRouteParseCache()
//{
@ -178,24 +213,24 @@ namespace ShardingCore6x
// _virtualTable.RouteTo(new ShardingTableRouteConfig(queryable: queryable1));
// }
//}
[Benchmark]
public async Task NoShardingFirstOrDefaultAsync()
{
for (int i = 0; i < N; i++)
{
var next = new Random().Next(1, 7000000).ToString();
var firstOrDefaultAsync = await _defaultDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Id == next);
}
}
[Benchmark]
public async Task ShardingFirstOrDefaultAsync()
{
for (int i = 0; i < N; i++)
{
var next = new Random().Next(1, 7000000).ToString();
var firstOrDefaultAsync = await _defaultShardingDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Id == next);
}
}
//[Benchmark]
//public async Task NoShardingFirstOrDefaultAsync()
//{
// for (int i = 0; i < N; i++)
// {
// var next = new Random().Next(1, 7000000).ToString();
// var firstOrDefaultAsync = await _defaultDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Id == next);
// }
//}
//[Benchmark]
//public async Task ShardingFirstOrDefaultAsync()
//{
// for (int i = 0; i < N; i++)
// {
// var next = new Random().Next(1, 7000000).ToString();
// var firstOrDefaultAsync = await _defaultShardingDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Id == next);
// }
//}
//[Benchmark]
//public async Task NoShardingIndexFirstOrDefaultAsync()
//{
@ -216,120 +251,120 @@ namespace ShardingCore6x
// var firstOrDefaultAsync = await _defaultShardingDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Id == next);
// }
//}
[Benchmark]
public async Task NoShardingNoIndexFirstOrDefaultAsync()
{
for (int i = 0; i < N; i++)
{
var firstOrDefaultAsync1 = await _defaultDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 0);
var firstOrDefaultAsync2 = await _defaultDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 999999);
}
}
//[Benchmark]
//public async Task NoShardingNoIndexFirstOrDefaultAsync()
//{
// for (int i = 0; i < N; i++)
// {
// var firstOrDefaultAsync1 = await _defaultDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 0);
// var firstOrDefaultAsync2 = await _defaultDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 999999);
// }
//}
[Benchmark]
public async Task ShardingNoIndexFirstOrDefaultAsync()
{
for (int i = 0; i < N; i++)
{
var firstOrDefaultAsync1 = await _defaultShardingDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 0);
var firstOrDefaultAsync2 = await _defaultShardingDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 999999);
}
}
[Benchmark]
public async Task NoShardingNoIndexCountAsync()
{
for (int i = 0; i < N; i++)
{
var firstOrDefaultAsync1 = await _defaultDbContext.Set<Order>().CountAsync(o => o.Amount == 0);
var firstOrDefaultAsync2 = await _defaultDbContext.Set<Order>().CountAsync(o => o.Amount == 999999);
}
}
//[Benchmark]
//public async Task ShardingNoIndexFirstOrDefaultAsync()
//{
// for (int i = 0; i < N; i++)
// {
// var firstOrDefaultAsync1 = await _defaultShardingDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 0);
// var firstOrDefaultAsync2 = await _defaultShardingDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 999999);
// }
//}
//[Benchmark]
//public async Task NoShardingNoIndexCountAsync()
//{
// for (int i = 0; i < N; i++)
// {
// var firstOrDefaultAsync1 = await _defaultDbContext.Set<Order>().CountAsync(o => o.Amount == 0);
// var firstOrDefaultAsync2 = await _defaultDbContext.Set<Order>().CountAsync(o => o.Amount == 999999);
// }
//}
[Benchmark]
public async Task ShardingNoIndexCountAsync()
{
for (int i = 0; i < N; i++)
{
var firstOrDefaultAsync1 = await _defaultShardingDbContext.Set<Order>().CountAsync(o => o.Amount == 0);
var firstOrDefaultAsync2 = await _defaultShardingDbContext.Set<Order>().CountAsync(o => o.Amount == 999999);
}
}
[Benchmark]
public async Task NoShardingNoIndexFirstOrDefaultAsync0w()
{
for (int i = 0; i < N; i++)
{
var firstOrDefaultAsync = await _defaultDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 0);
}
}
[Benchmark]
public async Task ShardingNoIndexFirstOrDefaultAsync0w()
{
for (int i = 0; i < N; i++)
{
var firstOrDefaultAsync = await _defaultShardingDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 0);
}
}
[Benchmark]
public async Task NoShardingNoIndexFirstOrDefaultAsync99w()
{
for (int i = 0; i < N; i++)
{
var firstOrDefaultAsync = await _defaultDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 999999);
}
}
[Benchmark]
public async Task ShardingNoIndexFirstOrDefaultAsync99w()
{
for (int i = 0; i < N; i++)
{
var firstOrDefaultAsync = await _defaultShardingDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 999999);
}
}
//[Benchmark]
//public async Task ShardingNoIndexCountAsync()
//{
// for (int i = 0; i < N; i++)
// {
// var firstOrDefaultAsync1 = await _defaultShardingDbContext.Set<Order>().CountAsync(o => o.Amount == 0);
// var firstOrDefaultAsync2 = await _defaultShardingDbContext.Set<Order>().CountAsync(o => o.Amount == 999999);
// }
//}
//[Benchmark]
//public async Task NoShardingNoIndexFirstOrDefaultAsync0w()
//{
// for (int i = 0; i < N; i++)
// {
// var firstOrDefaultAsync = await _defaultDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 0);
// }
//}
//[Benchmark]
//public async Task ShardingNoIndexFirstOrDefaultAsync0w()
//{
// for (int i = 0; i < N; i++)
// {
// var firstOrDefaultAsync = await _defaultShardingDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 0);
// }
//}
//[Benchmark]
//public async Task NoShardingNoIndexFirstOrDefaultAsync99w()
//{
// for (int i = 0; i < N; i++)
// {
// var firstOrDefaultAsync = await _defaultDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 999999);
// }
//}
//[Benchmark]
//public async Task ShardingNoIndexFirstOrDefaultAsync99w()
//{
// for (int i = 0; i < N; i++)
// {
// var firstOrDefaultAsync = await _defaultShardingDbContext.Set<Order>().FirstOrDefaultAsync(o => o.Amount == 999999);
// }
//}
[Benchmark]
public async Task NoShardingNoIndexLikeToListAsync()
{
for (int i = 0; i < N; i++)
{
var next = new Random().Next(1, 7000000).ToString();
var firstOrDefaultAsync = await _defaultDbContext.Set<Order>().Where(o => o.Body.Contains(next)).ToListAsync();
}
}
//[Benchmark]
//public async Task NoShardingNoIndexLikeToListAsync()
//{
// for (int i = 0; i < N; i++)
// {
// var next = new Random().Next(1, 7000000).ToString();
// var firstOrDefaultAsync = await _defaultDbContext.Set<Order>().Where(o => o.Body.Contains(next)).ToListAsync();
// }
//}
[Benchmark]
public async Task ShardingNoIndexLikeToListAsync()
{
for (int i = 0; i < N; i++)
{
var next = new Random().Next(1, 7000000).ToString();
var firstOrDefaultAsync = await _defaultShardingDbContext.Set<Order>().Where(o => o.Body.Contains(next)).ToListAsync();
}
}
[Benchmark]
public async Task NoShardingNoIndexToListAsync()
{
for (int i = 0; i < N; i++)
{
var next = new Random().Next(1, 7000000);
var firstOrDefaultAsync = await _defaultDbContext.Set<Order>().Where(o => o.Amount == next).ToListAsync();
}
}
//[Benchmark]
//public async Task ShardingNoIndexLikeToListAsync()
//{
// for (int i = 0; i < N; i++)
// {
// var next = new Random().Next(1, 7000000).ToString();
// var firstOrDefaultAsync = await _defaultShardingDbContext.Set<Order>().Where(o => o.Body.Contains(next)).ToListAsync();
// }
//}
//[Benchmark]
//public async Task NoShardingNoIndexToListAsync()
//{
// for (int i = 0; i < N; i++)
// {
// var next = new Random().Next(1, 7000000);
// var firstOrDefaultAsync = await _defaultDbContext.Set<Order>().Where(o => o.Amount == next).ToListAsync();
// }
//}
[Benchmark]
public async Task ShardingNoIndexToListAsync()
{
for (int i = 0; i < N; i++)
{
var next = new Random().Next(1, 7000000);
var firstOrDefaultAsync = await _defaultShardingDbContext.Set<Order>().Where(o => o.Amount == next).ToListAsync();
}
}
//[Benchmark]
//public async Task ShardingNoIndexToListAsync()
//{
// for (int i = 0; i < N; i++)
// {
// var next = new Random().Next(1, 7000000);
// var firstOrDefaultAsync = await _defaultShardingDbContext.Set<Order>().Where(o => o.Amount == next).ToListAsync();
// }
//}
//[Benchmark]
//public void ShardingRouteFirstOrDefault()
//{

View File

@ -1,9 +1,9 @@
:start
::定义版本
set EFCORE2=2.3.1.65
set EFCORE3=3.3.1.65
set EFCORE5=5.3.1.65
set EFCORE6=6.3.1.65
set EFCORE2=2.3.1.66
set EFCORE3=3.3.1.66
set EFCORE5=5.3.1.66
set EFCORE6=6.3.1.66
::删除所有bin与obj下的文件
@echo off

View File

@ -17,6 +17,15 @@ namespace Sample.SqlServerShardingDataSource.Controllers
{
_myDbContext = myDbContext;
}
/// <summary>
/// 动态追加分库
/// </summary>
/// <returns></returns>
//public IActionResult Queryabc()
//{
// DbContextHelper.CreateSubDb("X", "Data Source=localhost;Initial Catalog=EFCoreShardingDataSourceDBX;Integrated Security=True;");
// return Ok();
//}
public async Task<IActionResult> Query()
{
var sysUser =await _myDbContext.Set<SysUser>().Where(o=>o.Id=="1").FirstOrDefaultAsync();

View File

@ -0,0 +1,142 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Sample.SqlServerShardingDataSource.Entities;
using ShardingCore;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources.PhysicDataSources;
using ShardingCore.Core.VirtualDatabase.VirtualTables;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
using ShardingCore.Core.VirtualTables;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.TableCreator;
namespace Sample.SqlServerShardingDataSource
{
public class DbContextHelper
{
public static void CreateSubDb(string dataSourceName, string connectionString)
{
var _entityMetadataManager = ShardingContainer.GetService<IEntityMetadataManager<MyDbContext>>();
var _virtualDataSource = ShardingContainer.GetService<IVirtualDataSource<MyDbContext>>();
var _virtualTableManager = ShardingContainer.GetService<IVirtualTableManager<MyDbContext>>();
var _tableCreator = ShardingContainer.GetService<IShardingTableCreator<MyDbContext>>();
using (var serviceScope = ShardingContainer.ServiceProvider.CreateScope())
{
_virtualDataSource.AddPhysicDataSource(new DefaultPhysicDataSource(dataSourceName, connectionString, false));
var virtualDataSourceRoute = _virtualDataSource.GetRoute(typeof(Order));
virtualDataSourceRoute.AddDataSourceName(dataSourceName);
using var context = (DbContext)serviceScope.ServiceProvider.GetService(typeof(MyDbContext));
EnsureCreated(context, dataSourceName);
foreach (var entity in context.Model.GetEntityTypes())
{
var entityType = entity.ClrType;
if (_entityMetadataManager.IsShardingTable(entityType))
{
var virtualTable = _virtualTableManager.GetVirtualTable(entityType);
//创建表
CreateDataTable(dataSourceName, virtualTable);
}
else
{
_tableCreator.CreateTable(dataSourceName, entityType, string.Empty);
}
}
}
}
private static void CreateDataTable(string dataSourceName, IVirtualTable virtualTable)
{
var _tableCreator = ShardingContainer.GetService<IShardingTableCreator<MyDbContext>>();
var entityMetadata = virtualTable.EntityMetadata;
foreach (var tail in virtualTable.GetVirtualRoute().GetAllTails())
{
if (NeedCreateTable(entityMetadata))
{
try
{
//添加物理表
virtualTable.AddPhysicTable(new DefaultPhysicTable(virtualTable, tail));
_tableCreator.CreateTable(dataSourceName, entityMetadata.EntityType, tail);
}
catch (Exception ex)
{
//if (!_shardingConfigOption.IgnoreCreateTableError.GetValueOrDefault())
//{
// _logger.LogWarning(ex,
// $"table :{virtualTable.GetVirtualTableName()}{entityMetadata.TableSeparator}{tail} will created.");
//}
//TODO: 记录异常日志
System.Diagnostics.Trace.TraceError($"DbContextHelper-->CreateDataTable ERROR: {ex}");
}
}
else
{
//添加物理表
virtualTable.AddPhysicTable(new DefaultPhysicTable(virtualTable, tail));
}
}
}
private static bool NeedCreateTable(EntityMetadata entityMetadata)
{
if (entityMetadata.AutoCreateTable.HasValue)
{
if (entityMetadata.AutoCreateTable.Value)
return entityMetadata.AutoCreateTable.Value;
else
{
if (entityMetadata.AutoCreateDataSourceTable.HasValue)
return entityMetadata.AutoCreateDataSourceTable.Value;
}
}
if (entityMetadata.AutoCreateDataSourceTable.HasValue)
{
if (entityMetadata.AutoCreateDataSourceTable.Value)
return entityMetadata.AutoCreateDataSourceTable.Value;
else
{
if (entityMetadata.AutoCreateTable.HasValue)
return entityMetadata.AutoCreateTable.Value;
}
}
//return _shardingConfigOption.CreateShardingTableOnStart.GetValueOrDefault();
return true;
}
private static void EnsureCreated(DbContext context, string dataSourceName)
{
var _routeTailFactory = ShardingContainer.GetService<IRouteTailFactory>();
if (context is IShardingDbContext shardingDbContext)
{
var dbContext = shardingDbContext.GetDbContext(dataSourceName, false, _routeTailFactory.Create(string.Empty));
var modelCacheSyncObject = dbContext.GetModelCacheSyncObject();
var acquire = System.Threading.Monitor.TryEnter(modelCacheSyncObject, TimeSpan.FromSeconds(3));
if (!acquire)
{
throw new ShardingCoreException("cant get modelCacheSyncObject lock");
}
try
{
dbContext.RemoveDbContextRelationModelThatIsShardingTable();
dbContext.Database.EnsureCreated();
dbContext.RemoveModelCache();
}
finally
{
System.Threading.Monitor.Exit(modelCacheSyncObject);
}
}
}
}
}

View File

@ -65,6 +65,5 @@ namespace Sample.SqlServerShardingDataSource
}
}
}
}
}

View File

@ -0,0 +1,18 @@
using Sample.SqlServerShardingDataSource.Entities;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.VirtualRoutes.Mods;
namespace Sample.SqlServerShardingDataSource.VirtualRoutes
{
public class OrderRoute:AbstractSimpleShardingModKeyStringVirtualTableRoute<Order>
{
public OrderRoute() : base(2, 3)
{
}
public override void Configure(EntityMetadataTableBuilder<Order> builder)
{
builder.ShardingProperty(o => o.Id);
}
}
}

View File

@ -92,6 +92,9 @@ namespace ShardingCore.Bootstrapers
}
if (_shardingConfigOption.TryGetVirtualTableRoute<TEntity>(out var virtualTableRouteType))
{
if (!typeof(TShardingDbContext).IsShardingTableDbContext())
throw new ShardingCoreInvalidOperationException(
$"{typeof(TShardingDbContext)} is not impl {nameof(IShardingTableDbContext)},not support sharding table");
var entityMetadataTableBuilder = EntityMetadataTableBuilder<TEntity>.CreateEntityMetadataTableBuilder(entityMetadata);
//配置属性分表信息
EntityMetadataHelper.Configure(entityMetadataTableBuilder);

View File

@ -5,6 +5,7 @@ using System.Text;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using ShardingCore.Exceptions;
using ShardingCore.Sharding;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.Sharding.ReadWriteConfigurations;
@ -74,33 +75,32 @@ namespace ShardingCore.DIExtensions
_shardingCoreConfigBuilder.ShardingConfigOption.ReadWriteDefaultPriority,
_shardingCoreConfigBuilder.ShardingConfigOption.ReadWriteDefaultEnable,
_shardingCoreConfigBuilder.ShardingConfigOption.ReadConnStringGetStrategy));
bool isLoop = false;
if (_shardingCoreConfigBuilder.ShardingConfigOption.ReadStrategyEnum == ReadStrategyEnum.Loop)
{
services
.AddSingleton<IShardingConnectionStringResolver<TShardingDbContext>,
LoopShardingConnectionStringResolver<TShardingDbContext>>(sp =>
{
var readConnString = _shardingCoreConfigBuilder.ShardingConfigOption.ReadConnStringConfigure(sp);
var readWriteLoopConnectors = readConnString.Select(o => new ReadWriteLoopConnector(o.Key, o.Value));
return new LoopShardingConnectionStringResolver<TShardingDbContext>(
readWriteLoopConnectors);
});
isLoop = true;
}
else if (_shardingCoreConfigBuilder.ShardingConfigOption.ReadStrategyEnum == ReadStrategyEnum.Random)
{
services
.AddSingleton<IShardingConnectionStringResolver<TShardingDbContext>,
RandomShardingConnectionStringResolver<TShardingDbContext>>(sp =>
{
var readConnString = _shardingCoreConfigBuilder.ShardingConfigOption.ReadConnStringConfigure(sp);
var readWriteRandomConnectors = readConnString.Select(o => new ReadWriteRandomConnector(o.Key, o.Value));
return new RandomShardingConnectionStringResolver<TShardingDbContext>(
readWriteRandomConnectors);
});
isLoop = false;
}
else
{
throw new ShardingCoreInvalidOperationException($"unknow ReadStrategyEnum confgure:{_shardingCoreConfigBuilder.ShardingConfigOption.ReadStrategyEnum}");
}
services
.AddSingleton<IShardingConnectionStringResolver<TShardingDbContext>,
ReadWriteShardingConnectionStringResolver<TShardingDbContext>>(sp =>
{
var readConnString = _shardingCoreConfigBuilder.ShardingConfigOption.ReadConnStringConfigure(sp);
var readWriteLoopConnectors = readConnString.Select(o => (IReadWriteConnector)(isLoop ? new ReadWriteLoopConnector(o.Key, o.Value) : new ReadWriteRandomConnector(o.Key, o.Value)));
return new ReadWriteShardingConnectionStringResolver<TShardingDbContext>(
readWriteLoopConnectors);
});
services.TryAddSingleton<IShardingReadWriteManager, ShardingReadWriteManager>();
services.AddSingleton<IShardingReadWriteAccessor, ShardingReadWriteAccessor<TShardingDbContext>>();

View File

@ -32,6 +32,11 @@ namespace ShardingCore.Infrastructures
{
return Interlocked.CompareExchange(ref runStatus, running, unrunning) == unrunning;
}
public bool IsRunning()
{
return runStatus == running;
}
/// <summary>
///
/// </summary>

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ShardingCore.Sharding.ReadWriteConfigurations.Abstractions
{
public interface IReadWriteAppendConnectionString
{
bool AddReadConnectionString(string dataSourceName,string connectionString);
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ShardingCore.Sharding.ReadWriteConfigurations.Abstractions
{
public interface IReadWriteConnector
{
/// <summary>
/// 数据源
/// </summary>
public string DataSourceName { get; }
/// <summary>
/// 获取链接字符串
/// </summary>
/// <returns></returns>
public string GetConnectionString();
/// <summary>
/// 添加链接字符串
/// </summary>
/// <param name="connectionString"></param>
/// <returns></returns>
public bool AddConnectionString(string connectionString);
}
}

View File

@ -22,5 +22,12 @@ namespace ShardingCore.Sharding.ReadWriteConfigurations.Abstractions
{
bool ContainsReadWriteDataSourceName(string dataSourceName);
string GetConnectionString(string dataSourceName);
/// <summary>
/// 添加数据源从库读字符串
/// </summary>
/// <param name="dataSourceName"></param>
/// <param name="connectionString"></param>
/// <returns></returns>
bool AddConnectionString(string dataSourceName, string connectionString);
}
}

View File

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ShardingCore.Infrastructures;
using ShardingCore.Sharding.ReadWriteConfigurations.Abstractions;
namespace ShardingCore.Sharding.ReadWriteConfigurations.Connectors.Abstractions
{
public abstract class AbstractionReadWriteConnector:IReadWriteConnector
{
protected List<string> ConnectionStrings { get;}
protected int Length { get; private set; }
private readonly string _tempConnectionString;
private readonly OneByOneChecker _oneByOneChecker = new OneByOneChecker();
public AbstractionReadWriteConnector(string dataSourceName,IEnumerable<string> connectionStrings)
{
DataSourceName = dataSourceName;
ConnectionStrings = connectionStrings.ToList();
Length = ConnectionStrings.Count;
_tempConnectionString = ConnectionStrings[0];
}
public string DataSourceName { get; }
public string GetConnectionString()
{
//没有必要用太过于复杂的锁简单的操作简单的锁最简单的了
if (_oneByOneChecker.IsRunning())
{
return _tempConnectionString;
}
else
{
return DoGetConnectionString();
}
}
public abstract string DoGetConnectionString();
/// <summary>
/// 动态添加数据源
/// </summary>
/// <param name="connectionString"></param>
/// <returns></returns>
public bool AddConnectionString(string connectionString)
{
if (_oneByOneChecker.Start())
{
try
{
//是其他线程充分返回Connection并且感知到当前已在进行写入操作
Thread.SpinWait(1);
ConnectionStrings.Add(connectionString);
Length = ConnectionStrings.Count;
return true;
}
finally
{
_oneByOneChecker.Stop();
}
}
return false;
}
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using ShardingCore.Sharding.ReadWriteConfigurations.Connectors.Abstractions;
namespace ShardingCore.Sharding.ReadWriteConfigurations
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/9/18 17:27:44
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ReadWriteLoopConnector: AbstractionReadWriteConnector
{
private long _seed = 0;
public ReadWriteLoopConnector(string dataSourceName, IEnumerable<string> connectionStrings):base(dataSourceName,connectionStrings)
{
}
public override string DoGetConnectionString()
{
if (Length == 1)
return ConnectionStrings[0];
var newValue = Interlocked.Increment(ref _seed);
var next = (int)(newValue % Length);
if (next < 0)
return ConnectionStrings[Math.Abs(next)];
return ConnectionStrings[next];
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ShardingCore.Helpers;
using ShardingCore.Sharding.ReadWriteConfigurations.Connectors.Abstractions;
namespace ShardingCore.Sharding.ReadWriteConfigurations
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/9/18 20:58:42
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ReadWriteRandomConnector:AbstractionReadWriteConnector
{
public ReadWriteRandomConnector(string dataSourceName,IEnumerable<string> connectionStrings):base(dataSourceName,connectionStrings)
{
}
public override string DoGetConnectionString()
{
if (Length == 1)
return ConnectionStrings[0];
var next = RandomHelper.Next(0, Length);
return ConnectionStrings[next];
}
}
}

View File

@ -1,47 +0,0 @@
using ShardingCore.Sharding.ReadWriteConfigurations.Abstractions;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Exceptions;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Sharding.ReadWriteConfigurations
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/9/6 14:39:23
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class LoopShardingConnectionStringResolver<TShardingDbContext> : IShardingConnectionStringResolver<TShardingDbContext> where TShardingDbContext : DbContext, IShardingDbContext
{
private readonly ConcurrentDictionary<string, ReadWriteLoopConnector> _connectors =
new ConcurrentDictionary<string, ReadWriteLoopConnector>();
public LoopShardingConnectionStringResolver(IEnumerable<ReadWriteLoopConnector> connectors)
{
var enumerator = connectors.GetEnumerator();
while (enumerator.MoveNext())
{
var currentConnector = enumerator.Current;
if (currentConnector != null)
_connectors.TryAdd(currentConnector.DataSourceName, currentConnector);
}
}
public bool ContainsReadWriteDataSourceName(string dataSourceName)
{
return _connectors.ContainsKey(dataSourceName);
}
public string GetConnectionString(string dataSourceName)
{
if (!_connectors.TryGetValue(dataSourceName, out var connector))
throw new ShardingCoreInvalidOperationException($"read write connector not found, data source name:[{dataSourceName}]");
return connector.GetConnectionString();
}
}
}

View File

@ -16,7 +16,7 @@ namespace ShardingCore.Sharding.ReadWriteConfigurations
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ReadWriteConnectionStringManager<TShardingDbContext> : IConnectionStringManager<TShardingDbContext> where TShardingDbContext : DbContext, IShardingDbContext
public class ReadWriteConnectionStringManager<TShardingDbContext> : IConnectionStringManager<TShardingDbContext>, IReadWriteAppendConnectionString where TShardingDbContext : DbContext, IShardingDbContext
{
private IShardingConnectionStringResolver<TShardingDbContext> _shardingConnectionStringResolver;
private readonly IVirtualDataSource<TShardingDbContext> _virtualDataSource;
@ -34,5 +34,10 @@ namespace ShardingCore.Sharding.ReadWriteConfigurations
return _shardingConnectionStringResolver.GetConnectionString(dataSourceName);
}
public bool AddReadConnectionString(string dataSourceName, string connectionString)
{
return _shardingConnectionStringResolver.AddConnectionString(dataSourceName, connectionString);
}
}
}

View File

@ -1,41 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ShardingCore.Sharding.ReadWriteConfigurations
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/9/18 17:27:44
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ReadWriteLoopConnector
{
private readonly string[] _connectionStrings;
private readonly int _length;
private long _seed = 0;
public ReadWriteLoopConnector(string dataSourceName, IEnumerable<string> connectionStrings)
{
DataSourceName = dataSourceName;
_connectionStrings = connectionStrings.ToArray();
_length = _connectionStrings.Length;
}
public string DataSourceName { get; }
public string GetConnectionString()
{
if (_length == 1)
return _connectionStrings[0];
var newValue = Interlocked.Increment(ref _seed);
var next = (int)(newValue % _length);
if (next < 0)
return _connectionStrings[Math.Abs(next)];
return _connectionStrings[next];
}
}
}

View File

@ -1,37 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ShardingCore.Helpers;
namespace ShardingCore.Sharding.ReadWriteConfigurations
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/9/18 20:58:42
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ReadWriteRandomConnector
{
private readonly string[] _connectionStrings;
private readonly int _length;
public ReadWriteRandomConnector(string dataSourceName,IEnumerable<string> connectionStrings)
{
DataSourceName = dataSourceName;
_connectionStrings = connectionStrings.ToArray();
_length = _connectionStrings.Length;
}
public string GetConnectionString()
{
if (_length == 1)
return _connectionStrings[0];
var next = RandomHelper.Next(0, _length);
return _connectionStrings[next];
}
public string DataSourceName { get; }
}
}

View File

@ -3,27 +3,20 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Exceptions;
using ShardingCore.Helpers;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.Sharding.ReadWriteConfigurations.Abstractions;
namespace ShardingCore.Sharding.ReadWriteConfigurations
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/9/6 14:22:55
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class RandomShardingConnectionStringResolver<TShardingDbContext> : IShardingConnectionStringResolver<TShardingDbContext> where TShardingDbContext : DbContext, IShardingDbContext
public class ReadWriteShardingConnectionStringResolver<TShardingDbContext> : IShardingConnectionStringResolver<TShardingDbContext> where TShardingDbContext : DbContext, IShardingDbContext
{
private readonly ConcurrentDictionary<string, ReadWriteRandomConnector> _connectors =
new ConcurrentDictionary<string, ReadWriteRandomConnector>();
private readonly ConcurrentDictionary<string, IReadWriteConnector> _connectors =
new ConcurrentDictionary<string, IReadWriteConnector>();
public RandomShardingConnectionStringResolver(IEnumerable<ReadWriteRandomConnector> connectors)
public ReadWriteShardingConnectionStringResolver(IEnumerable<IReadWriteConnector> connectors)
{
var enumerator = connectors.GetEnumerator();
while (enumerator.MoveNext())
@ -46,5 +39,12 @@ namespace ShardingCore.Sharding.ReadWriteConfigurations
throw new ShardingCoreInvalidOperationException($"read write connector not found, data source name:[{dataSourceName}]");
return connector.GetConnectionString();
}
public bool AddConnectionString(string dataSourceName, string connectionString)
{
if (!_connectors.TryGetValue(dataSourceName, out var connector))
throw new ShardingCoreInvalidOperationException($"read write connector not found, data source name:[{dataSourceName}]");
return connector.AddConnectionString(connectionString);
}
}
}

View File

@ -38,8 +38,8 @@ namespace ShardingCore.Test
.Begin(o =>
{
#if DEBUG
//o.CreateShardingTableOnStart = true;
//o.EnsureCreatedWithOutShardingTable = true;
o.CreateShardingTableOnStart = true;
o.EnsureCreatedWithOutShardingTable = true;
#endif
o.AutoTrackEntity = true;
})