免费爱碰视频在线观看,九九精品国产屋,欧美亚洲尤物久久精品,1024在线观看视频亚洲

      在Saas系統(tǒng)下多租戶零腳本分表分庫(kù)讀寫(xiě)分離解決方案

      在Saas系統(tǒng)下多租戶零腳本分表分庫(kù)讀寫(xiě)分離解決方案

      前言

      您是否有以下場(chǎng)景:

      • 租戶系統(tǒng),數(shù)據(jù)庫(kù)級(jí)別隔離
      • 大數(shù)據(jù)量,需要分表分庫(kù)(動(dòng)態(tài)添加),分庫(kù)分表全自動(dòng)維護(hù)處理
      • 租戶之前可能需要使用不同的數(shù)據(jù)庫(kù)模式,譬如有些租戶要求用oracle,或者mmsql,或者mysql或者pgsql
      • 多租戶系統(tǒng)在不同的數(shù)據(jù)庫(kù)環(huán)境下需要維護(hù)的表結(jié)構(gòu)復(fù)雜繁瑣,需要維護(hù)許多腳本
      • 業(yè)務(wù)代碼需要進(jìn)行大范圍的妥協(xié)來(lái)適應(yīng)上述支持
      • 系統(tǒng)需要支持讀寫(xiě)分離(動(dòng)態(tài)添加)
      • 無(wú)需停機(jī)狀態(tài)實(shí)時(shí)添加租戶(租戶線上簽約)

      當(dāng)然我是一開(kāi)始想先寫(xiě)這篇文章,但是寫(xiě)著寫(xiě)著發(fā)現(xiàn)有些時(shí)候這個(gè)問(wèn)題就來(lái)了,譬如多數(shù)據(jù)庫(kù)下efcore默認(rèn)不支持遷移,經(jīng)過(guò)不斷地努力,大腦的思維宮殿我下意識(shí)就發(fā)現(xiàn)了解決方案,最終用一天時(shí)間解決了就是前面的一篇文章 EFCore高級(jí)Saas系統(tǒng)下單DbContext如何支持不同數(shù)據(jù)庫(kù)的遷移 那么我們?cè)挷欢嗾f(shuō)馬上開(kāi)始

      接下來(lái)我們將實(shí)現(xiàn)A,B,C三個(gè)租戶,其中A租戶我們使用MSSQL的訂單表使用按月分表,B租戶我們使用MYSQL的訂單表我們采用Id取模分表,C租戶我們使用MSSQL也是使用訂單按月分表但是起始時(shí)間和A不一樣

      管理租戶數(shù)據(jù)

      首先我們新建一個(gè)DbContext用來(lái)管理我們的租戶信息

      租戶用戶表

      首先我們新建一張租戶登錄的用戶表,每個(gè)用戶就是我們對(duì)外的租戶

      public class SysUser { public string Id { get; set; } public string Name { get; set; } public string Password { get; set; } public DateTime CreationTime { get; set; } public bool IsDeleted { get; set; } }

      租戶配置表

      然后我們新建一張租戶的配置信息表用來(lái)后續(xù)初始化配置

      public class SysUserTenantConfig { public string Id { get; set; } public string UserId { get; set; } /// /// 添加ShardingTenantOptions的Json包 /// public string ConfigJson { get; set; } public DateTime CreationTime { get; set; } public bool IsDeleted { get; set; } }

      定義租戶配置

      //為了滿足上述需求我們需要對(duì)數(shù)據(jù)庫(kù)和訂單分片方式進(jìn)行區(qū)分 public class ShardingTenantOptions { /// /// 默認(rèn)數(shù)據(jù)源名稱 /// public string DefaultDataSourceName { get; set;} /// /// 默認(rèn)數(shù)據(jù)庫(kù)地址 /// public string DefaultConnectionString { get; set; } /// /// 數(shù)據(jù)庫(kù)類型 /// public DbTypeEnum DbType { get; set; } /// /// 分片模式 取模還是按月 /// public OrderShardingTypeEnum OrderShardingType { get; set; } /// /// 按月分片其實(shí)時(shí)間 /// public DateTime BeginTimeForSharding { get; set; } /// /// 分片遷移的命名空間 /// public string MigrationNamespace { get; set; } } public enum DbTypeEnum { MSSQL = 1, MYSQL = 2 }  public enum OrderShardingTypeEnum  {   Mod=1,   ByMonth=2 }

      租戶持久化DbContext

      新建一個(gè)dbcontext用來(lái)存儲(chǔ)我們的租戶信息,當(dāng)然你也可以使用文件或者redis之類的都行

      public class IdentityDbContext:DbContext { public IdentityDbContext(DbContextOptions options):base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ApplyConfiguration(new SysUserMap()); modelBuilder.ApplyConfiguration(new SysUserTenantConfigMap()); } }

      這樣我們就完成了租戶信息的存儲(chǔ)

      租戶管理者

        我們擁有了租戶信息持久化的數(shù)據(jù)后需要對(duì)租戶信息的使用進(jìn)行配置

      首先我們新建一個(gè)接口可以用來(lái)管理租戶信息

      public interface ITenantManager { /// /// 獲取所有的租戶 /// /// List GetAll(); /// /// 獲取當(dāng)前租戶 /// /// TenantContext GetCurrentTenantContext(); /// /// 添加租戶信息 /// /// /// /// bool AddTenantSharding(string tenantId, IShardingRuntimeContext shardingRuntimeContext); /// /// 創(chuàng)建租戶環(huán)境 /// /// /// TenantScope CreateScope(string tenantId); } //租戶的默認(rèn)管理實(shí)現(xiàn) public class DefaultTenantManager:ITenantManager { private readonly ITenantContextAccessor _tenantContextAccessor; private readonly ConcurrentDictionary _cache = new(); public DefaultTenantManager(ITenantContextAccessor tenantContextAccessor) { _tenantContextAccessor = tenantContextAccessor; } public List GetAll() { return _cache.Keys.ToList(); } public TenantContext GetCurrentTenantContext() { return _tenantContextAccessor.TenantContext; } public bool AddTenantSharding(string tenantId, IShardingRuntimeContext shardingRuntimeContext) { return _cache.TryAdd(tenantId, shardingRuntimeContext); } public TenantScope CreateScope(string tenantId) { if (!_cache.TryGetValue(tenantId, out var shardingRuntimeContext)) { throw new InvalidOperationException(“未找到對(duì)應(yīng)租戶的配置”); } _tenantContextAccessor.TenantContext = new TenantContext(shardingRuntimeContext); return new TenantScope(_tenantContextAccessor); } } //當(dāng)前租戶上下文訪問(wèn)者 public interface ITenantContextAccessor { TenantContext? TenantContext { get; set; } } //當(dāng)前租戶上下文訪問(wèn)者實(shí)現(xiàn) public class TenantContextAccessor:ITenantContextAccessor { private static readonly AsyncLocal _tenantContext = new AsyncLocal(); public TenantContext? TenantContext { get => _tenantContext.Value; set => _tenantContext.Value = value; } } //租戶上下文 public class TenantContext { private readonly IShardingRuntimeContext _shardingRuntimeContext; public TenantContext(IShardingRuntimeContext shardingRuntimeContext) { _shardingRuntimeContext = shardingRuntimeContext; } public IShardingRuntimeContext GetShardingRuntimeContext() { return _shardingRuntimeContext; } } //用來(lái)切換實(shí)現(xiàn)當(dāng)前操作租戶環(huán)境 public class TenantScope:IDisposable { public TenantScope(ITenantContextAccessor tenantContextAccessor) { TenantContextAccessor = tenantContextAccessor; } public ITenantContextAccessor TenantContextAccessor { get; } public void Dispose() { } }折疊

      構(gòu)思ShardingCore如何不通過(guò)依賴注入使用

      其實(shí)ShardingCore可以默認(rèn)不在依賴注入中進(jìn)行依賴注入,首先我們看下普通情況下ShardingCore如何實(shí)現(xiàn)非依賴注入獲取分片上下文

      var shardingRuntimeContext = new ShardingRuntimeBuilder() .UseRouteConfig(o => { o.AddShardingTableRoute(); }).UseConfig(o => { o.ThrowIfQueryRouteNotMatch = false; o.UseShardingQuery((conStr, builder) => { builder.UseMySql(conStr, new MySqlServerVersion(new Version())) .UseLoggerFactory(efLogger) .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); }); o.UseShardingTransaction((connection, builder) => { builder .UseMySql(connection, new MySqlServerVersion(new Version())) .UseLoggerFactory(efLogger) .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); }); o.AddDefaultDataSource(“ds0”, “server=127.0.0.1;port=3306;database=dbdbd0;userid=root;password=root;”); o.UseShardingMigrationConfigure(b => { b.ReplaceService(); }); }).ReplaceService(ServiceLifetime.Singleton) .Build();

      這樣我們就獲得了IShardingRuntimeContext,將不同的IShardingRuntimeContext放到不同的數(shù)據(jù)庫(kù)中我們就可以實(shí)現(xiàn)不同的租戶了

      訂單表

      public class Order { public string Id { get; set; } public string Name { get; set; } public DateTime CreationTime { get; set; } public bool IsDeleted { get; set; } }

      租戶DbContext

      public class TenantDbContext:AbstractShardingDbContext,IShardingTableDbContext { public TenantDbContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ApplyConfiguration(new OrderMap()); } public IRouteTail RouteTail { get; set; } }

      創(chuàng)建訂單路由

      訂單按月分片路由

      注意這邊我們簡(jiǎn)單的通過(guò)采用一個(gè)靜態(tài)字段來(lái)實(shí)現(xiàn)

      public class OrderMonthTableRoute:AbstractSimpleShardingMonthKeyDateTimeVirtualTableRoute { private readonly ShardingTenantOptions _shardingTenantOptions; public OrderMonthTableRoute(ShardingTenantOptions shardingTenantOptions) { _shardingTenantOptions = shardingTenantOptions; } public override void Configure(EntityMetadataTableBuilder builder) { builder.ShardingProperty(o => o.CreationTime); } public override bool AutoCreateTableByTime() { return true; } public override DateTime GetBeginTime() { return _shardingTenantOptions.BeginTimeForSharding; } }

      訂單取模分片路由

      public class OrderModTableRoute:AbstractSimpleShardingModKeyStringVirtualTableRoute{ private readonly ShardingTenantOptions _shardingTenantOptions; public OrderModTableRoute(ShardingTenantOptions shardingTenantOptions) : base(2, 5) { _shardingTenantOptions = shardingTenantOptions; } public override void Configure(EntityMetadataTableBuilder builder) { builder.ShardingProperty(o => o.Id); }}

      實(shí)現(xiàn)多數(shù)據(jù)庫(kù)的code-first遷移

      具體參考之前的博客EFCore高級(jí)Saas系統(tǒng)下單DbContext如何支持不同數(shù)據(jù)庫(kù)的遷移

      https://www.cnblogs.com/xuejiaming/p/16510482.html

      分片創(chuàng)建者

      public interface IShardingBuilder{ IShardingRuntimeContext Build(ShardingTenantOptions tenantOptions);}public class DefaultShardingBuilder:IShardingBuilder{ public static readonly ILoggerFactory efLogger = LoggerFactory.Create(builder => { builder.AddFilter((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information).AddConsole(); }); private readonly IServiceProvider _serviceProvider; public DefaultShardingBuilder(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public IShardingRuntimeContext Build(ShardingTenantOptions tenantOptions) { var shardingRuntimeBuilder = new ShardingRuntimeBuilder() .UseRouteConfig(o => { if (tenantOptions.OrderShardingType == OrderShardingTypeEnum.Mod) { o.AddShardingTableRoute(); } if (tenantOptions.OrderShardingType == OrderShardingTypeEnum.ByMonth) { o.AddShardingTableRoute(); } }).UseConfig(o => { o.ThrowIfQueryRouteNotMatch = false; o.UseShardingQuery((conStr, builder) => { if (tenantOptions.DbType == DbTypeEnum.MYSQL) { builder.UseMySql(conStr, new MySqlServerVersion(new Version())) .UseMigrationNamespace(new MySqlMigrationNamespace()); } if (tenantOptions.DbType == DbTypeEnum.MSSQL) { builder.UseSqlServer(conStr) .UseMigrationNamespace(new SqlServerMigrationNamespace()); } builder.UseLoggerFactory(efLogger) .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking) .ReplaceService(); }); o.UseShardingTransaction((connection, builder) => { if (tenantOptions.DbType == DbTypeEnum.MYSQL) { builder .UseMySql(connection, new MySqlServerVersion(new Version())); //.UseMigrationNamespace(new MySqlMigrationNamespace());//遷移只會(huì)用connection string創(chuàng)建所以可以不加 } if (tenantOptions.DbType == DbTypeEnum.MSSQL) { builder.UseSqlServer(connection); //.UseMigrationNamespace(new SqlServerMigrationNamespace()); } builder.UseLoggerFactory(efLogger) .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); }); o.AddDefaultDataSource(tenantOptions.DefaultDataSourceName,tenantOptions.DefaultConnectionString); //注意這個(gè)遷移必須要十分重要 //注意這個(gè)遷移必須要十分重要 //注意這個(gè)遷移必須要十分重要 //注意這個(gè)遷移必須要十分重要 o.UseShardingMigrationConfigure(b => { if (tenantOptions.DbType == DbTypeEnum.MYSQL) { b.ReplaceService(); } if (tenantOptions.DbType == DbTypeEnum.MSSQL) { b.ReplaceService(); } }); }).AddServiceConfigure(s => { //IShardingRuntimeContext內(nèi)部的依賴注入 s.AddSingleton(tenantOptions); }); if (tenantOptions.DbType == DbTypeEnum.MYSQL) { shardingRuntimeBuilder.ReplaceService(ServiceLifetime .Singleton); } if (tenantOptions.DbType == DbTypeEnum.MSSQL) { shardingRuntimeBuilder.ReplaceService(ServiceLifetime .Singleton); } return shardingRuntimeBuilder.Build(_serviceProvider); }}折疊

      到此為止基本上我們已經(jīng)完成了多租戶的大部分配置了,jwt部分就不在這邊贅述了因?yàn)橹坝袑?shí)現(xiàn)過(guò)

      Startup

      主要關(guān)鍵的啟動(dòng)點(diǎn)我們應(yīng)該怎么配置呢

      啟動(dòng)初始化租戶

      首先我們需要針對(duì)程序啟動(dòng)后進(jìn)行租戶的初始化操作

      public static class TenantExtension { public static void InitTenant(this IServiceProvider serviceProvider) { var tenantManager = serviceProvider.GetRequiredService(); var shardingBuilder = serviceProvider.GetRequiredService(); using (var scope = serviceProvider.CreateScope()) { var identityDbContext = scope.ServiceProvider.GetRequiredService(); identityDbContext.Database.Migrate(); var sysUserTenantConfigs = identityDbContext.Set().ToList(); if (sysUserTenantConfigs.Any()) { foreach (var sysUserTenantConfig in sysUserTenantConfigs) { var shardingTenantOptions = JsonConvert.DeserializeObject(sysUserTenantConfig.ConfigJson); var shardingRuntimeContext = shardingBuilder.Build(shardingTenantOptions); tenantManager.AddTenantSharding(sysUserTenantConfig.UserId, shardingRuntimeContext); } } } var tenantIds = tenantManager.GetAll(); foreach (var tenantId in tenantIds) { using(tenantManager.CreateScope(tenantId)) using (var scope = serviceProvider.CreateScope()) { var shardingRuntimeContext = tenantManager.GetCurrentTenantContext().GetShardingRuntimeContext(); //開(kāi)啟定時(shí)任務(wù) shardingRuntimeContext.UseAutoShardingCreate(); var tenantDbContext = scope.ServiceProvider.GetService(); // tenantDbContext.Database.Migrate(); //補(bǔ)償表 shardingRuntimeContext.UseAutoTryCompensateTable(); } } } }

      請(qǐng)求租戶中間件

      為了讓我們的所有請(qǐng)求都可以使用指定對(duì)應(yīng)的租戶數(shù)據(jù)庫(kù)

      public class TenantSelectMiddleware { private readonly RequestDelegate _next; private readonly ITenantManager _tenantManager; public TenantSelectMiddleware(RequestDelegate next,ITenantManager tenantManager) { _next = next; _tenantManager = tenantManager; } /// /// 1.中間件的方法必須叫Invoke,且為public,非static。 /// 2.Invoke方法第一個(gè)參數(shù)必須是HttpContext類型。 /// 3.Invoke方法必須返回Task。 /// 4.Invoke方法可以有多個(gè)參數(shù),除HttpContext外其它參數(shù)會(huì)嘗試從依賴注入容器中獲取。 /// 5.Invoke方法不能有重載。 /// /// Author : Napoleon /// Created : 2020/1/30 21:30 public async Task Invoke(HttpContext context) { if (context.Request.Path.ToString().StartsWith(“/api/tenant”, StringComparison.CurrentCultureIgnoreCase)) { if (!context.User.Identity.IsAuthenticated) { await _next(context); return; } var tenantId = context.User.Claims.FirstOrDefault((o) => o.Type == “uid”)?.Value; if (string.IsNullOrWhiteSpace(tenantId)) { await DoUnAuthorized(context, “not found tenant id”); return; } using (_tenantManager.CreateScope(tenantId)) { await _next(context); } } else { await _next(context); } } private async Task DoUnAuthorized(HttpContext context, string msg) { context.Response.StatusCode = 403; await context.Response.WriteAsync(msg); } }折疊

      編寫(xiě)登錄注冊(cè)操作

      startup處配置

      [Route(“api/[controller]/[action]”)] [ApiController] [AllowAnonymous] public class PassportController : ControllerBase { private readonly IServiceProvider _serviceProvider; private readonly IdentityDbContext _identityDbContext; private readonly ITenantManager _tenantManager; private readonly IShardingBuilder _shardingBuilder; public PassportController(IServiceProvider serviceProvider, IdentityDbContext identityDbContext, ITenantManager tenantManager, IShardingBuilder shardingBuilder) { _serviceProvider = serviceProvider; _identityDbContext = identityDbContext; _tenantManager = tenantManager; _shardingBuilder = shardingBuilder; } [HttpPost] public async Task Register(RegisterRequest request) { if (await _identityDbContext.Set().AnyAsync(o => o.Name == request.Name)) return BadRequest(“user not exists”); var sysUser = new SysUser() { Id = Guid.NewGuid().ToString(“n”), Name = request.Name, Password = request.Password, CreationTime = DateTime.Now }; var shardingTenantOptions = new ShardingTenantOptions() { DbType = request.DbType, OrderShardingType = request.OrderShardingType, BeginTimeForSharding = request.BeginTimeForSharding.Value, DefaultDataSourceName = “ds0”, DefaultConnectionString = GetDefaultString(request.DbType, sysUser.Id) }; var sysUserTenantConfig = new SysUserTenantConfig() { Id = Guid.NewGuid().ToString(“n”), UserId = sysUser.Id, CreationTime = DateTime.Now, ConfigJson = JsonConvert.SerializeObject(shardingTenantOptions) }; await _identityDbContext.AddAsync(sysUser); await _identityDbContext.AddAsync(sysUserTenantConfig); await _identityDbContext.SaveChangesAsync(); var shardingRuntimeContext = _shardingBuilder.Build(shardingTenantOptions); _tenantManager.AddTenantSharding(sysUser.Id, shardingRuntimeContext); using (_tenantManager.CreateScope(sysUser.Id)) using (var scope = _serviceProvider.CreateScope()) { var runtimeContext = _tenantManager.GetCurrentTenantContext().GetShardingRuntimeContext(); runtimeContext.UseAutoShardingCreate(); //啟動(dòng)定時(shí)任務(wù) var tenantDbContext = scope.ServiceProvider.GetService(); tenantDbContext.Database.Migrate(); runtimeContext.UseAutoTryCompensateTable(); } return Ok(); } [HttpPost] public async Task Login(LoginRequest request) { var sysUser = await _identityDbContext.Set() .FirstOrDefaultAsync(o => o.Name == request.Name && o.Password == request.Password); if (sysUser == null) return BadRequest(“name or password error”); //秘鑰,就是標(biāo)頭,這里用Hmacsha256算法,需要256bit的密鑰 var securityKey = new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(“123123!@#!@#123123”)), SecurityAlgorithms.HmacSha256); //Claim,JwtRegisteredClaimNames中預(yù)定義了好多種默認(rèn)的參數(shù)名,也可以像下面的Guid一樣自己定義鍵名. //ClaimTypes也預(yù)定義了好多類型如role、email、name。Role用于賦予權(quán)限,不同的角色可以訪問(wèn)不同的接口 //相當(dāng)于有效載荷 var claims = new Claim[] { new Claim(JwtRegisteredClaimNames.Iss, “https://localhost:5000”), new Claim(JwtRegisteredClaimNames.Aud, “api”), new Claim(“id”, Guid.NewGuid().ToString(“n”)), new Claim(“uid”, sysUser.Id), }; SecurityToken securityToken = new JwtSecurityToken( signingCredentials: securityKey, expires: DateTime.Now.AddHours(2), //過(guò)期時(shí)間 claims: claims ); var token = new JwtSecurityTokenHandler().WriteToken(securityToken); return Ok(token); } private string GetDefaultString(DbTypeEnum dbType, string userId) { switch (dbType) { case DbTypeEnum.MSSQL: return #34;Data Source=localhost;Initial Catalog=DB{userId};Integrated Security=True;”; case DbTypeEnum.MYSQL: return #34;server=127.0.0.1;port=3306;database=DB{userId};userid=root;password=L6yBtV6qNENrwBy7;”; default: throw new NotImplementedException(); } } } public class RegisterRequest { public string Name { get; set; } public string Password { get; set; } public DbTypeEnum DbType { get; set; } public OrderShardingTypeEnum OrderShardingType { get; set; } public DateTime? BeginTimeForSharding { get; set; } } public class LoginRequest { public string Name { get; set; } public string Password { get; set; } }折疊

      啟動(dòng)配置

      var builder = WebApplication.CreateBuilder(args);// Add services to the container.builder.Services.AddControllers();builder.Services.AddAuthentication();#region 用戶系統(tǒng)配置builder.Services.AddDbContext(o => o.UseSqlServer(“Data Source=localhost;Initial Catalog=IdDb;Integrated Security=True;”));//生成密鑰var keyByteArray = Encoding.ASCII.GetBytes(“123123!@#!@#123123”);var signingKey = new SymmetricSecurityKey(keyByteArray);//認(rèn)證參數(shù)builder.Services.AddAuthentication(“Bearer”) .AddJwtBearer(o => { o.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = signingKey, ValidateIssuer = true, ValidIssuer = “https://localhost:5000”, ValidateAudience = true, ValidAudience = “api”, ValidateLifetime = true, ClockSkew = TimeSpan.Zero, RequireExpirationTime = true, }; });#endregionbuilder.Services.AddSingleton();builder.Services.AddSingleton();builder.Services.AddSingleton();#region 配置ShardingCorevar provider = builder.Configuration.GetValue(“Provider”, “UnKnown”);//Add-Migration InitialCreate -Context TenantDbContext -OutputDir MigrationsSqlServer -Args “–provider SqlServer”//Add-Migration InitialCreate -Context TenantDbContext -OutputDir MigrationsMySql -Args “–provider MySql”builder.Services.AddDbContext((sp, b) =>{ var tenantManager = sp.GetRequiredService(); var currentTenantContext = tenantManager.GetCurrentTenantContext(); //如果有上下文那么創(chuàng)建租戶dbcontext否則就是啟動(dòng)命令A(yù)dd-Migration if (currentTenantContext != null) { var shardingRuntimeContext = currentTenantContext.GetShardingRuntimeContext(); b.UseDefaultSharding(shardingRuntimeContext); } if (args.IsNotEmpty()) { //命令啟動(dòng)時(shí)為了保證Add-Migration正常運(yùn)行 if (provider == “MySql”) { b.UseMySql(“server=127.0.0.1;port=3306;database=TenantDb;userid=root;password=L6yBtV6qNENrwBy7;”, new MySqlServerVersion(new Version())) .UseMigrationNamespace(new MySqlMigrationNamespace()) .ReplaceService(); return; } if (provider == “SqlServer”) { b.UseSqlServer(“Data Source=localhost;Initial Catalog=TenantDb;Integrated Security=True;”) .UseMigrationNamespace(new SqlServerMigrationNamespace()) .ReplaceService(); return; } }});#endregionvar app = builder.Build();//初始化啟動(dòng)配置租戶信息app.Services.InitTenant();app.UseAuthorization();//在認(rèn)證后啟用租戶選擇中間件app.UseMiddleware();app.MapControllers();app.Run();折疊

      添加遷移腳本

      持久化identity遷移

      多租戶SqlServer版本

      多租戶MySql版本

      啟動(dòng)程序

      啟動(dòng)程序我們發(fā)現(xiàn)IdentityDbContext已經(jīng)創(chuàng)建好了,并且支持了自動(dòng)遷移

      創(chuàng)建A租戶

      { “Name”:”A”, “Password”:”A”, “DbType”:1, “OrderShardingType”:2, “BeginTimeForSharding”:”2022-01-01″, “MigrationNamespace”:”ShardingCoreMultiTenantSys.Migrations.SqlServer”}

      注意:MigrationNamespace應(yīng)該自動(dòng)生成,這邊只是為了演示方便沒(méi)寫(xiě)

      完成

      創(chuàng)建B租戶

      { “Name”:”B”, “Password”:”B”, “DbType”:2, “OrderShardingType”:1, “BeginTimeForSharding”:”2022-01-01″, “MigrationNamespace”:”ShardingCoreMultiTenantSys.Migrations.Myql”}

      完美創(chuàng)建

      創(chuàng)建C租戶

      { “Name”:”C”, “Password”:”C”, “DbType”:1, “OrderShardingType”:2, “BeginTimeForSharding”:”2022-06-01″, “MigrationNamespace”:”ShardingCoreMultiTenantSys.Migrations.SqlServer”}

      C租戶完美創(chuàng)建并且和A租戶采用一樣的分片規(guī)則不一樣的分片起始時(shí)間

      分別對(duì)abc進(jìn)行crud

      首先獲取token,然后插入A租戶

      B租戶

      C租戶

      最后完成

      文章來(lái)自https://www.cnblogs.com/xuejiaming/p/16508446.html

      鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場(chǎng),版權(quán)歸原作者所有,如有侵權(quán)請(qǐng)聯(lián)系管理員(admin#wlmqw.com)刪除。
      用戶投稿
      上一篇 2022年7月27日 09:21
      下一篇 2022年7月27日 09:21

      相關(guān)推薦

      • 分享4條發(fā)微商朋友圈的方法(微商朋友圈應(yīng)該怎么發(fā))

        對(duì)于微商朋友來(lái)說(shuō),朋友圈的重要性不言而喻了。 那么微商的朋友圈到底該怎么發(fā)呢? 為什么同樣是經(jīng)營(yíng)一個(gè)朋友圈,有的微商看起來(lái)逼格滿滿,實(shí)際效果也不錯(cuò);而有的卻動(dòng)都不動(dòng)就被屏蔽甚至拉黑…

        2022年11月27日
      • 淘寶工廠店的東西是正品嗎?淘寶工廠店為什么便宜

        淘工廠直營(yíng)店其實(shí)就是鏈接淘寶賣家與工廠的平臺(tái),直接對(duì)接工廠型的商家,店鋪里的東西大部分價(jià)格都會(huì)很低。那么,淘工廠直營(yíng)店靠譜嗎? 淘工廠直營(yíng)店是靠譜的,但售后問(wèn)題可能得不到很好的保障…

      • 存儲(chǔ)過(guò)程語(yǔ)法(sql server存儲(chǔ)過(guò)程語(yǔ)法)

        今天小編給各位分享存儲(chǔ)過(guò)程語(yǔ)法的知識(shí),其中也會(huì)對(duì)sql server存儲(chǔ)過(guò)程語(yǔ)法進(jìn)行解釋,如果能碰巧解決你現(xiàn)在面臨的問(wèn)題,別忘了關(guān)注本站,現(xiàn)在開(kāi)始吧! oracle存儲(chǔ)過(guò)程基本語(yǔ)法…

        2022年11月26日
      • 計(jì)算機(jī)網(wǎng)絡(luò)技術(shù)論文(計(jì)算機(jī)網(wǎng)絡(luò)技術(shù)論文七千字)

        今天小編給各位分享計(jì)算機(jī)網(wǎng)絡(luò)技術(shù)論文的知識(shí),其中也會(huì)對(duì)計(jì)算機(jī)網(wǎng)絡(luò)技術(shù)論文七千字進(jìn)行解釋,如果能碰巧解決你現(xiàn)在面臨的問(wèn)題,別忘了關(guān)注本站,現(xiàn)在開(kāi)始吧! 計(jì)算機(jī)網(wǎng)絡(luò)方面的論文3000字…

        2022年11月26日
      • 《寶可夢(mèng)朱紫》夢(mèng)特性怎么獲得?隱藏特性獲取方法推薦

        寶可夢(mèng)朱紫里有很多寶可夢(mèng)都是擁有夢(mèng)特性會(huì)變強(qiáng)的寶可夢(mèng),很多玩家不知道夢(mèng)特性怎么獲得,下面就給大家?guī)?lái)寶可夢(mèng)朱紫隱藏特性獲取方法推薦,感興趣的小伙伴一起來(lái)看看吧,希望能幫助到大家。 …

        2022年11月25日
      • 《寶可夢(mèng)朱紫》奇魯莉安怎么進(jìn)化?奇魯莉安進(jìn)化方法分享

        寶可夢(mèng)朱紫中的奇魯莉安要怎么進(jìn)化呢?很多玩家都不知道,下面就給大家?guī)?lái)寶可夢(mèng)朱紫奇魯莉安進(jìn)化方法分享,感興趣的小伙伴一起來(lái)看看吧,希望能幫助到大家。 奇魯莉安進(jìn)化方法分享 奇魯莉安…

        2022年11月25日
      • 5+3疫情防控從哪天開(kāi)始算(遼寧疫情防控最新政策)

        最近有關(guān)國(guó)內(nèi)各地的疫情大家也都有在持續(xù)關(guān)注,目前國(guó)內(nèi)各地疫情隔離時(shí)間也根據(jù)二十條防控措施有了新的調(diào)整。那么,5+3疫情防控從哪天開(kāi)始算?對(duì)于密接的5+3隔離時(shí)間計(jì)算大家還是比較關(guān)心…

        2022年11月25日
      • 藍(lán)碼怎么變綠碼需要幾天(藍(lán)碼怎么變綠碼需要幾天)

        大家都知道健康碼的顏色有紅碼、綠碼、黃碼,近日湖南健康碼上線“藍(lán)碼”,不少小伙伴發(fā)現(xiàn)自己健康碼變藍(lán)了,都想趕緊恢復(fù)綠碼,那么藍(lán)碼怎么變綠碼需要幾天?下面小編為大家?guī)?lái)藍(lán)碼變綠碼需要…

        2022年11月25日
      • 數(shù)字看亮點(diǎn)!前十月我國(guó)造船三大指標(biāo)繼續(xù)全球領(lǐng)先

        央視網(wǎng)消息:工業(yè)和信息化部最新數(shù)據(jù)顯示,今年1—10月,我國(guó)造船三大指標(biāo)繼續(xù)保持全球領(lǐng)先。隨著生產(chǎn)節(jié)奏加快,船企產(chǎn)業(yè)集中度進(jìn)一步提升。 2022年1—10月,全國(guó)造船完工量、新接訂…

        2022年11月25日
      • 前十個(gè)月我國(guó)造船業(yè)三大指標(biāo)穩(wěn)居世界第一

        今年1—10月,我國(guó)造船業(yè)在國(guó)際市場(chǎng)的份額繼續(xù)穩(wěn)居世界第一。一批高技術(shù)高附加值船舶實(shí)現(xiàn)了批量接單、批量生產(chǎn)。 近日,中國(guó)船舶上海船舶研究設(shè)計(jì)院又新接了韓國(guó)船東三艘汽車運(yùn)輸船的設(shè)計(jì)追…

        2022年11月25日

      聯(lián)系我們

      聯(lián)系郵箱:admin#wlmqw.com
      工作時(shí)間:周一至周五,10:30-18:30,節(jié)假日休息