zoukankan      html  css  js  c++  java
  • EF多租户实例:快速实现分库分表

    前言

    来到这篇随笔,我们继续演示如何实现EF多租户。

    今天主要是演示多租户下的变形,为下图所示

    实施

    项目结构

    这次我们的示例项目进行了精简,仅有一个API项目,直接包含所有代码。

    其中Controller,StoreContext,Entity都完全和以往的示例一模一样,这里就不再过多介绍了。

    具有主要区别的是 CombinedConnectionGenerator 和 Startup 

    代码解释

    1. 首先要关注的是作为入口的 Startup ,还是一个套路,分别在 ConfigureService 注册EF多租户, 在 Configure 配置中间件。

    ConfigureService 还是一贯的简单。但是注意这里使用的 AddMySqlPerTable 这个模式。

    在混合的模式中,需要已最小的单元作为服务注册。由于这次是数据库和数据表混合模式,所以需要用数据表来注册。

    1 public void ConfigureServices(IServiceCollection services)
    2 {
    3     services.AddScoped<IConnectionGenerator, CombindedConnectionGenerator>();
    4     services.AddMySqlPerTable<StoreDbContext>(settings =>
    5     {
    6         settings.ConnectionPrefix = "mysql_";
    7     });
    8     services.AddControllers();
    9 }

    Configure的使用更加简单,只需要添加中间件 TenantInfoMiddleware 即可。

     1 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
     2 {
     3     if (env.IsDevelopment())
     4     {
     5         app.UseDeveloperExceptionPage();
     6     }
     7 
     8     app.UseMiddleware<TenantInfoMiddleware>();
     9 
    10     app.UseRouting();
    11 
    12     app.UseEndpoints(endpoints =>
    13     {
    14         endpoints.MapControllers();
    15     });
    16 }

    2. 这次需要自己实现 ConnectionGenerator 

    关键点有2个,

    第一个关键点,由于我们的类库是同时支持多个DbContext的,所以需要有TenantKey去区分。由于有种特殊情况,需要一个 ConnectionGenerator 同时支持多个 DbContext ,所以这里提供了 MatchTenantKey 方法作为补充的判断依据。

    可以看出来,我们这里TenantKey 为空,所以一般都不会匹配中。示例中完全是依靠 MatchTenantKey 来做匹配的。

    第二个关键点,GetConnection 作为最主要的逻辑方法,通过对TenantName 的数字部分进行取模,最终拼接处ConnectionString的键值

    并且通过 Configuration 获取连接字符串

     1 public class CombindedConnectionGenerator : IConnectionGenerator
     2 {
     3     private readonly IConfiguration configuration;
     4     public string TenantKey => "";
     5 
     6     public CombindedConnectionGenerator(IConfiguration configuration)
     7     {
     8         this.configuration = configuration;
     9     }
    10 
    11 
    12     public string GetConnection(TenantOption option, TenantInfo tenantInfo)
    13     {
    14         var span = tenantInfo.Name.AsSpan();
    15         if (span.Length > 4 && int.TryParse(span[5].ToString(), out var number))
    16         {
    17             return configuration.GetConnectionString($"{option.ConnectionPrefix}container{number % 2 + 1}");
    18         }
    19         throw new NotSupportedException("tenant invalid");
    20     }
    21 
    22     public bool MatchTenantKey(string tenantKey)
    23     {
    24         return true;
    25     }
    26 }

    检验结果

    检验结果我觉得已经没有必要的,都是同样的套路,主要的区别是,之前的只有一个数据库,或者多个数据库

    这次的混合模式,主要是一个数据库作为一个container,里面可以同时包含多个product数据表。

    Container1

    Container2

    总结

    其实这个例子也是非常简单的,目的是让每个人都能快速应用复杂的分库分表

    下一篇文章将会通过多租户实现读写分离。

    关于这个文章的所有代码,已经同步到Github

    https://github.com/woailibain/kiwiho.EFcore.MultiTenant/tree/master/example/mix_mode/kiwiho.EFcore.MultiTenant.MixMode

  • 相关阅读:
    8-6.布局元素实战
    Unity3D NGUI插件(3.12/2018/2019)
    GoLang 数据结构-二叉树
    GoLang 数据结构-哈希表(散列表)
    GoLang 四大经典排序(冒泡排序,选择排序,插入排序,快速排序)写法及执行效率
    GoLang 数据结构-单向链表,双向链表,单向环形链表
    GoLang 数据结构-环形队列
    GoLang 数据结构-稀疏数组
    GoLang 海量用户聊天系统(TCP-Socket网络编程+Redis数据库+协程)
    GoLang 使用协程和管道获取随机数
  • 原文地址:https://www.cnblogs.com/woailibian/p/12632019.html
Copyright © 2011-2022 走看看