.NET Core中完美解决多租户分库分表的问题

前几天有人想做一个多租户的平台,每个租户一个库,可以进行水平扩展,应用端根据登录信息,切换到不同的租户库。

计划用 ef core 实现,他们说做不出来,需要动态创建 dbContext,不好实现。

然而这个使用 CRL 很轻松就能解决了。

以下为演示数据库,有两个库 testdb 和 testdb2,查询结果如下

.NET Core 中完美解决多租户分库分表的问题

目标

根据传入登录信息连不不同的库,查询返回结果,如登录人为 01,返回 d1.default,登录人为 02 返回 d2.default

实际上这个需求就是分库分表的实现,通过设置数据库/表映射关系,根据传入的定位数据进行匹配,找到正确的库表配置,生成数据访问对象

以 core 控制台程序为例

class Program
{
    static IServiceProvider provider;
    static Program()
    {
        var services = new ServiceCollection();
        services.AddCRL<DBLocationCreator>();
        services.AddScoped<Code.Sharding.MemberManage>();
        provider = services.BuildServiceProvider();
        provider.UseCRL();
    }
    static void Main(string[] args)
    {
    label1:
        var instance = provider.GetService<Code.Sharding.MemberManage>();
        var data = new Code.Sharding.MemberSharding();
        data.Code = "01";
        instance.SetLocation(data);
        var find1 = instance.QueryItem(b => b.Id > 0)?.Name;
        Console.WriteLine($"定位数据输入{data.Code},查询值为{find1}");
        data.Code = "02";
        instance.SetLocation(data);
        var find2 = instance.QueryItem(b => b.Id > 0)?.Name;
        Console.WriteLine($"定位数据输入{data.Code},查询值为{find2}");
        Console.ReadLine();
        goto label1;
    }
}

上面代码中,通过 SetLocation 方法传入定位数据 Code,通过 QueryItem 方法查询出数据并打印出来

通过 services.AddCRL<DBLocationCreator>()注入定位配置,DBLocationCreator 继承了接口 IDBLocationCreator

这里完全符合 core 注入规范,可以通过配置或数据库存储动态读取定位设置

public class DBLocationCreator : IDBLocationCreator
{
    ISettingConfigBuilder _settingConfigBuilder;
    public DBLocationCreator(ISettingConfigBuilder settingConfigBuilder)
    {
        _settingConfigBuilder = settingConfigBuilder;
    }
    public void Init()
    {
        //自定义定位 _settingConfigBuilder.RegisterLocation<Code.Sharding.MemberSharding>((t, a) =>
        {
            var tableName = t.TableName;
            var dbName = a.Code == "02" ? "testdb2" : "testdb";
            var dataBase = $"Data Source=.;Initial Catalog={dbName};User ID=sa;Password=123";
            //返回定位库和表名
            return new CRL.Sharding.Location(dataBase, tableName);
        });
        _settingConfigBuilder.RegisterDBAccessBuild(dbLocation =>
        {
            var connectionString = "Data Source=.;Initial Catalog=testdb;User ID=sa;Password=123";
            if (dbLocation.ShardingLocation != null)
            {
                connectionString = dbLocation.ShardingLocation.DataBaseSource;
            }
            return new CRL.DBAccessBuild(DBType.MSSQL, connectionString);
        });
    }
}

在 Init 方法里,实现了两个操作,通过 RegisterLocation 定义如何根据定位数据 Code,返回不同的库/表

通过 RegisterDBAccessBuild 实现数据访问

对象定义

public class MemberSharding : CRL.IModel
{
    [CRL.Attribute.Field(KeepIdentity=true)]//保持插入主键
    public int Id
    {
        get;
        set;
    }
    public string Name
    {
        get;
        set;
    }
    public string Code;
}
public class MemberManage : CRL.Sharding.BaseProvider<MemberSharding>
{
}

运行测试程序,结果输出为

.NET Core 中完美解决多租户分库分表的问题

上面代码通过自定义定位参数和定位规则,没有任何耦合,调用也很简单,完美达到了预期效果。

测试代码地址:

https://github.com/CRL2020/CRL.NetStandard/tree/master/Test/CRLCoreTest

 

© 版权声明

☆ END ☆
喜欢就点个赞吧
点赞2 分享
图片正在生成中,请稍后...