Furion分表分庫我也要happy coding

薛家明發表於2021-11-24

Furion分表分庫整合ShardingCore

ShardingCore

ShardingCore 易用、簡單、高效能、普適性,是一款擴充套件針對efcore生態下的分表分庫的擴充套件解決方案,支援efcore2+的所有版本,支援efcore2+的所有資料庫、支援自定義路由、動態路由、高效能分頁、讀寫分離的一款元件,如果你喜歡這元件或者這個元件對你有幫助請點選下發star讓更多的.neter可以看到使用


Github Star 助力dotnet 生態 Gitee Star


背景

隨著.net6的釋出,陸陸續續的框架都已經開始支援了,ShardingCore也不例外,為了推動.net生態,也為了讓更多的的人瞭解.net下其實也有分表分庫的解決方案,所以打算寫一篇關於ShardingCore整合到其他框架的思路。

Fourin框架大家應該也是比較清楚的,作者也是一個樂於開源有著開源精神的人,秉著大家都是熱愛開源的所以決定助Fourin一臂之力(蹭一下熱度)。隨著上次的AbpVNext的"完美"整合ShardingCore後,這次帶來的就是Furion下的ShardingCore整合。

efcore下完美的分表分庫解決方案,支援任意efcore的整合框架,完美支援或者需要稍作修改即可完美支援,並不需要讓你有任何使用的學習成本,幾乎做到不修改現有efcore程式碼的前提下讓你的程式完美支援分表分庫。真正做到“零”程式碼修改。

新建Furion專案

首先我們已目前Furion最新版本為例v3.0.5,新建一個空的aspnetcore web api的net6專案,當然也支援efcore2+的所有aspnetcore版本。

然後我們新增ShardingCoreefcore.SqlServer

新建dbcontext

這邊看了Furion的使用方法和Abp一樣需要繼承一個他自己的DbContext叫做AppDbContext,但是沒有關西。因為ShardingCore是基於介面來實現的,所以不存在多繼承問題,只是我們需要自行實現Furion的ShardingDbContext的抽象版本原始碼地址 AppShardingDbContext

簡單的說下就是如果你是需要繼承某個dbcontext的那麼就需要自己實現三個介面IShardingDbContext, ISupportShardingTransaction, ISupportShardingReadWrite分別是分表分庫的核心介面,支援事務,支援讀寫分離。

具體已經幫你們抽象好了只需要複製程式碼就可以了。

做好了準備工作我們開始新建dbcontext


    [AppDbContext("SqlServerConnectionString", DbProvider.SqlServer)]
    public class DefaultDbContext : AppShardingDbContext<DefaultDbContext>,IShardingTableDbContext
    {
        public DefaultDbContext(DbContextOptions<DefaultDbContext> options) : base(options)
        {
        }

        public IRouteTail RouteTail { get; set; }
    }

建立todoitem物件


    public class TodoItem:IPrivateEntity
    {
        public string Id { get; set; }
        public string Name { get; set; }
    }

  

這邊我們將TodoItemId做成取模分表

配置dbcontext


    [AppDbContext("SqlServerConnectionString", DbProvider.SqlServer)]
    public class DefaultDbContext : AppShardingDbContext<DefaultDbContext>,IShardingTableDbContext
    {
        public DefaultDbContext(DbContextOptions<DefaultDbContext> options) : base(options)
        {
        }

        public IRouteTail RouteTail { get; set; }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<TodoItem>(entity =>
            {
                entity.HasKey(o => o.Id);
                entity.Property(o => o.Id).IsRequired().IsUnicode(false).HasMaxLength(50).HasComment("Id");
                entity.Property(o => o.Name).IsRequired().HasMaxLength(50).HasComment("名稱");
                entity.ToTable(nameof(TodoItem));
            });
        }
    }

  

配置了todoitem的簡單配置,注意這邊不一定要這麼配置,也可以用Attribute+DbSet,也可以用FluentApi

建立TodoItem的分表路由

    public class TodoItemVirtualTableRoute : AbstractSimpleShardingModKeyStringVirtualTableRoute<TodoItem>
    {
        public TodoItemVirtualTableRoute() : base(2, 8)
        {
        }
        public override void Configure(EntityMetadataTableBuilder<TodoItem> builder)
        {
            builder.ShardingProperty(x => x.Id);
        }
    }

  這邊採用的是簡單取模通過建構函式傳入,具體可以參考文件就是分表字尾為2位數,模8也就是00,01.....07,一共8張表,ShardingProperty(x => x.Id)表示TodoItem的分表欄位為Id。

注意: 這邊只是為了簡單演示,你如果需要外部傳入可以自行通過實現AbstractShardingOperatorVirtualTableRoute來實現,並且路由建構函式支援單例的依賴注入

初始化Furion配置

AppStartup


    [AppStartup(600)]
    public sealed class SqlServerEntityFrameworkCoreStartup : AppStartup
    {
        public static readonly ILoggerFactory efLogger = LoggerFactory.Create(builder =>
        {
            builder.AddFilter((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information).AddConsole();
        });
        public void ConfigureServices(IServiceCollection services)
        {
            var connStr = DbProvider.GetConnectionString<DefaultDbContext>(/*這裡可寫可不寫*/);
            // 配置資料庫上下文,支援N個資料庫
            services.AddDatabaseAccessor(options =>
            {
                // 配置預設資料庫
                options.AddDb<DefaultDbContext>(o =>
                {
                    o.UseSqlServer(connStr).UseSharding<DefaultDbContext>().UseLoggerFactory(efLogger);
                });

            });
            services.AddShardingConfigure<DefaultDbContext>((s, builder) =>
            {
                builder.UseSqlServer(s).UseLoggerFactory(efLogger);
            }).Begin(o =>
            {
                o.CreateShardingTableOnStart = true;
                o.EnsureCreatedWithOutShardingTable = true;
                o.AutoTrackEntity = true;
            })
                 .AddShardingTransaction((connection, builder) =>
                     builder.UseSqlServer(connection).UseLoggerFactory(efLogger))
                 .AddDefaultDataSource("ds0", connStr)
                 .AddShardingTableRoute(o =>
                 {
                     o.AddShardingTableRoute<TodoItemVirtualTableRoute>();
                 }).End();
        }
    }

  通過官網我們可以知道如何針對Furion進行efcore的配置,這邊目前sharding-core不支援efcore的單例dbcontext,所以不建議使用單例。

額外配置:.UseSharding<DefaultDbContext>()僅需要配置dbcontext使用sharding原先的所有dbcontext的注入都可以不去管他

sharding-core的配置:AddShardingConfiguresharding-core在efcore的基礎上額外進行配置就可以支援分表分庫的擴充套件更多配置可以參考文件

Program


using ShardingCore.Bootstrapers;

var builder = WebApplication.CreateBuilder(args).Inject();

// Add services to the container.

builder.Services.AddControllers().AddInject();

var app = builder.Build();

// Configure the HTTP request pipeline.

app.UseAuthorization();

app.UseInject();
app.Services.GetRequiredService<IShardingBootstrapper>().Start();
app.MapControllers();

app.Run();

 注意:很多同學老是忘記啟動導致sharding-core沒法使用app.Services.GetRequiredService<IShardingBootstrapper>().Start(); 

編寫控制器

首先我們通過注入建構函式IRepository<TodoItem> todoItemRepository這是Furion提供的

其次我們編寫增刪改查介面

    [HttpGet]
    public async Task<IActionResult> Add()
    {
        await _todoItemRepository.InsertAsync(new TodoItem() { Id = Guid.NewGuid().ToString("n"), Name = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") });
        await _todoItemRepository.SaveNowAsync();
        return Ok();
    }
    [HttpGet]
    public async Task<IActionResult> List()
    {
        var list = await _todoItemRepository.AsQueryable().ToListAsync();
        return Ok(list);
    }
    [HttpGet]
    public async Task<IActionResult> First([FromQuery]string id)
    {
        var todoItem = await _todoItemRepository.FirstOrDefaultAsync(o => o.Id == id);
        return Ok(todoItem);
    }
    [HttpGet]
    public async Task<IActionResult> Update([FromQuery]string id)
    {
        var todoItem = await _todoItemRepository.FirstOrDefaultAsync(o => o.Id == id);
        todoItem.Name = "123";
        await _todoItemRepository.SaveNowAsync();
        return Ok(todoItem);
    }

啟動專案

因為預設為了測試ShardingCore配置了

 o.CreateShardingTableOnStart = true;
 o.EnsureCreatedWithOutShardingTable = true;

 所以啟動會幫我們建表並且建庫

新增

符合預期插入到了具體的hash%8的表

查詢所有

因為是獲取所有所以這邊會查詢所有的分表符合預期

獲取單條

獲取單條符合預期用的id取模所以用id去查詢會到指定的表裡面

更新

符合預期程式碼先查詢05表在更新05表並且使用的是追蹤更新

我們接著再來查詢一次看看是否真的修改了

到此為止我們的FurionShardingCore整合就完成了,當然這只是ShardingCore的冰山一角,最最最簡單的分表,如果你喜歡或者你認為ShardingCore有用那麼可以給個贊或者star嗎?開原作者希望自己開源的專案被更多人高人指點並且進步。也希望為.net下的分表分庫進行一份微薄之力。在efcore下我相信ShardingCore是在官方不支援efcore下最最最完美的解決方案。全程的使用程式碼體驗是0感知,並且支援所有使用efcore的框架,只要你配置好了完全不需要考慮,當然也有同學要槓,如果某些情況下我就是要指定某幾張表呢,ShardingCore也是支援的所以在自動情況下是“零”入侵業務程式碼的最優分表分庫方案,更多使用方式請查詢

github ShardingCore文件

gitee ShardingCore文件

最後專案原始碼

FurionShardingDemo

dotnet 天下第一 (大吼)

分表分庫元件求贊求star


部落格

QQ群:771630778

個人QQ:326308290(歡迎技術支援提供您寶貴的意見)

個人郵箱:326308290@qq.com

相關文章