Abp VNext 集成sharding-core 分表分库
ShardingCore?易用、簡單、高性能、普適性,是一款擴展針對efcore生態下的分表分庫的擴展解決方案,支持efcore2+的所有版本,支持efcore2+的所有數據庫、支持自定義路由、動態路由、高性能分頁、讀寫分離的一款組件,如果你喜歡這組件或者這個組件對你有幫助請點擊下發star讓更多的.neter可以看到使用
Gitee Star?助力dotnet 生態?Github Star
背景
你是否在使用efcore,你是否在使用abp,你是否對目前的分表十分厭惡,手動指定表讓你的代碼無辜多出很多膠水代碼,那么這次的文章可以很好的幫你解決掉當前的困難點,sharding-core?針對efcore的分庫分表讀寫分離的痛點進行擴展,可以完美集成到efcore生態的系統里面,無論你是abp還是其他使用efcore的框架,你確定真的不看一下嗎,如何集成abp當時我發布這個庫的時候就有很多人問我是否支持,我的回答是支持的,只是個人沒有時間去實現。這次已經實現了我這邊將分享下如何集成sharding-core到abp vnext中。
距離上一篇博客已經兩周了,在這兩周期間本人還是做了很多事情,針對優化sharding-core的使用和體驗,就在上周五傍晚的時候有個使用abp的同學聯系我,問我什么時候支持abp vnext,其實這個計劃我很早之前就在issue里面備注了,只是獲取用abp的同學沒有怎么關注這個類庫也沒人提出來,所以就擱置了。因為sharding-core是一款幾乎可以說可以集成到任何efcore生態下的所以原則上abp上集成應該是沒什么難度的,因為本人使用abp不是很多所以這邊自己按官方教程進行了初步的項目搭建,然后又用了一會功夫了解了abp源碼(之前有了解過)清楚了dbcontext的創建過程所以很快就繼承好了一個todoapp
接下來我將用一篇博客的篇幅來介紹如何將sharing-core集成到abp vnext中。
如何集成
abp項目創建/下載
我這邊是通過github進行了例子的todoapp?進行下載,下載后是一個集合例子,我們獲取TodoApp項目進行單獨處理,打開然后編譯。
注意如果你自己會新建那么也是一樣的
集成abp思路
用過abp的用戶都應該知道abp的dbcontext沒有什么不一樣,唯一需要注意的就是abp:只要你的dbcontext繼承至?public class TDbContext:AbpDbContext<TDbContext>那么就可以完美使用.
但是sharding-core的使用我們通過readme來查看發現sharidng-core:只要你的dbcontext繼承至public class TDbContext:AbstractShardingDbContext那么你就可以完美使用.
好家伙直接給想自己集成的同學搞蒙蔽了,c#又不是c艸沒有多繼承啊那怎么辦,但是這邊其實是有一個誤區的就是abp確實需要繼承abpdbcontext但是sharding-core是已接口作為依賴來開發的,所以我們只需要實現ISharingDbContext?這個接口就可以了如果需要事務在實現ISupportShardingTransaction
最終我們是通過實現一個抽象基類來繼承abpdbcntext并且實現sharding-core需要的接口?AbstractShardingAbpDbContext?這樣我們就可以在不破壞abp的同時又兼顧了sharding-core
注意:這邊sharing-core讓你們繼承AbstractShardingDbContext是因為重復寫這些接口的實現會很麻煩所以給你們寫了一個抽象方便你們使用
abp集成注意事項
通過源碼可以看出abp集成需要賦值lazyserviceprovider 因為abp的dbcontext是交由uow自己處理并且需要支持很多特性所以我們在創建dbcontext的時候需要對此處進行賦值注意點。
注意abp默認提供了IEntity<Guid>,IHasCreationTime屬性較為常用所以我們需要注意如何支持這兩種,因為當你用id取模分表或者創建時間分表的使用場景還是比較常見的所以我們需要支持。
因為在insert時如果sharding-core發現對應的分表字段為null就無法繼續執行下去,所以為了兼容abp需要支持兩個比較常見的需求
賦值依賴注入支持domain event等事件
自動屬性
了解sahrding-core針對dbcontext的分表支持
首先我們需要知道sharding-core是如何對一個普通的dbcontext進行支持的
如果你的dbcontext有用到以下任意一個接口那么集成起來可能需要自己去實現對應的接口
IDbSetSource 用來接管dbset
IQueryCompiler 用來接管查詢編譯
IDbContextTransactionManager 用來接管事務開啟
IRelationalTransactionFactory 用來接管事務的提交、回滾 和加入
IModelCacheKeyFactory 用來接管dbcontext的模型緩存
IModelCustomizer 用來接管dbcontext的模型初始化前后自定義
如果你的efcore想接入sharding-core并且如果你沒有對dbcontext的上述任何接口進行替換那么可以很容易就接入,如果你的efcore在創建的時候有針對上述的接口進行替換,就需要你自己手動進行兩邊的實現合并。
如何接入sharding-core
這邊我們假設你沒有對上述的dbcontextoptionbuilder的創建進行接口的替換那么你只需要進行如下操作就可以簡單接入sharding-core
首先就是默認創建dbcontext替換為sharding-core的配置
原先:
public void ConfigureServices(IServiceCollection services)services.AddDbContext<DefaultShardingTableDbContext>(o => o.UseSqlServer("Server=.;Database=TodoApp;Trusted_Connection=True"));現在:
public void ConfigureServices(IServiceCollection services)//1.先檢查dbcontext構造函數只允許 DbContextOptions<TodoAppDbContext> optionsShardingCoreHelper.CheckContextConstructors<DefaultShardingTableDbContext>(); //2.添加UseSharding<DefaultShardingTableDbContext>()讓依賴注入創建的dbcontext支持查詢插入事務的管理services.AddDbContext<DefaultShardingTableDbContext>(o=>o.UseSqlServer("Server=.;Database=TodoApp;Trusted_Connection=True").UseSharding<DefaultShardingTableDbContext>()); //3.添加分表配置new ShardingCoreConfigBuilder<DefaultShardingTableDbContext>(context.Services,((s, builder) =>{builder.UseSqlServer(s);} )).Begin(o =>{o.CreateShardingTableOnStart = false;o.EnsureCreatedWithOutShardingTable = false;o.AutoTrackEntity = true;}).AddShardingTransaction((connection, builder) =>builder.UseSqlServer(connection)).AddDefaultDataSource("ds0", "Server=.;Database=TodoApp;Trusted_Connection=True").AddShardingTableRoute(o =>{o.AddShardingTableRoute<ToDoItemVirtualTableRoute>();}).End();public void Configure(IApplicationBuilder app, IWebHostEnvironment env) //4.初始化分表配置var shardingBootstrapper = app.ApplicationServices.GetRequiredService<IShardingBootstrapper>();shardingBootstrapper.Start();綜上所述我們接入任何efcore的系統只需要進行4步(第一步都可以去掉只需要3步)就可以完美接入了,可以保證使用
abp正式接入替換
修改將todoitem表作為id取模來進行分表演示
修改TodoItem實體
默認TodoApp有一個TodoItem實體對象我們首先創建兩個空接口
//標識對應分表對像的i分表字段是id,是自動創建的guidpublic interface IShardingKeyIsGuId{} //標識對應的分表對應的分表字段是創建時間public interface IShardingKeyIsCreationTime{} //修改TodoItempublic class TodoItem : BasicAggregateRoot<Guid>,IShardingTable,IShardingKeyIsGuId{[ShardingTableKey]public override Guid Id { get; protected set; }public string Text { get; set; }}創建TodoItem的分表路由
通過繼承默認分表取模路由AbstractSimpleShardingModKeyStringVirtualTableRoute
//id取模雖然是string但是guid也是一樣的最多兩位就是00_99,按5來取模public class ToDoItemVirtualTableRoute:AbstractSimpleShardingModKeyStringVirtualTableRoute<TodoItem>{public ToDoItemVirtualTableRoute() : base(2, 5){}}實現抽象類修改TodoItemDbContext
實現?AbstractShardingAbpDbContext
public class TodoAppDbContext :AbstractShardingAbpDbContext<TodoAppDbContext>,IIdentityDbContext,ITenantManagementDbContext,IShardingTableDbContext修改實體TodoItem
public class TodoItem : BasicAggregateRoot<Guid>,IShardingTable,IShardingKeyIsGuId{[ShardingTableKey]public override Guid Id { get; protected set; }public string Text { get; set; }}其中別的接口都和sharding-core一致,為了支持abp的部分自動屬性這邊進行了新的接口添加用來標識當前的對象是通過什么方式來進行分表的,然后可以高效的通過接口來進行賦值,比如IShardingKeyIsGuId告訴系統是id為guid的進行分表的
public abstract class AbstractShardingAbpDbContext<TDbContext>... { ......private void CheckAndSetShardingKeyThatSupportAutoCreate<TEntity>(TEntity entity) where TEntity : class{if (entity is IShardingKeyIsGuId){if (entity is IEntity<Guid> guidEntity){if (guidEntity.Id != default){return;}var idProperty = entity.GetProperty(nameof(IEntity<Guid>.Id));var dbGeneratedAttr = ReflectionHelper.GetSingleAttributeOrDefault<DatabaseGeneratedAttribute>(idProperty);if (dbGeneratedAttr != null && dbGeneratedAttr.DatabaseGeneratedOption != DatabaseGeneratedOption.None){return;}EntityHelper.TrySetId(guidEntity,() => GuidGenerator.Create(),true);}}else if (entity is IShardingKeyIsCreationTime){AuditPropertySetter?.SetCreationProperties(entity);}} }添加虛擬路由
既然你講TodoItem進行了分表,那么你這邊需要告訴系統你是按怎么個規則進行分表的,假設我們默認按id取模那么可以繼承sharding-core默認提供的取模路由
public class ToDoItemVirtualTableRoute:AbstractSimpleShardingModKeyStringVirtualTableRoute<TodoItem>{public ToDoItemVirtualTableRoute() : base(2, 5){}}簡單說明就是分表后綴為2位數00-99,5代表模5也就是00,01,02,03,04
注意:?IShardingTableDbContext如果dbcontext需要實現分表功能必須實現IShardingTableDbContext
到目前為止我們的準備工作已經完成了,接下來需要進行codefirst的支持和具體項目的配置使用了
選中TodoApp.EntityFrameworkCore項目打開TodoAppDbContextFactory替換dbcontext的創建方法,主要是替換codefirst的建表語句
這邊是采用了EFCore.Sharding
主要代碼就是告訴efcore.tools如何創建對應的dbcontext
然后打開nuget控制臺
選中需要生成遷移的項目
啟動項設置為
執行命令
PM> Add-Migration InitTodoAppPM> update-database到此為止我們的code first已經完成了,系統會自動根據分表的配置來進行創建對應的sql語句
abp啟動
因為sharding-core是基于接口和dbcontext所以只要你的efcore那么基本上你的生態就可以接入sharding-core,主要就是注意1點
自定義替換DbContextOptions的部分服務
dbcontext的構造函數是DbContextOptions或者是他的泛型類
修改TodoAppEntityFrameworkCoreModule
public override void ConfigureServices(ServiceConfigurationContext context){......Configure<AbpDbContextOptions>(options =>{/* The main point to change your DBMS.* See also TodoAppDbContextFactory for EF Core tooling. */options.UseSqlServer();options.Configure<TodoAppDbContext>(context1 =>{context1.DbContextOptions.UseSqlServer("Server=.;Database=TodoApp;Trusted_Connection=True").UseSharding<TodoAppDbContext>();});});ShardingCoreHelper.CheckContextConstructors<TodoAppDbContext>();new ShardingCoreConfigBuilder<TodoAppDbContext>(context.Services,((s, builder) =>{builder.UseSqlServer(s);} )).Begin(o =>{o.CreateShardingTableOnStart = false;o.EnsureCreatedWithOutShardingTable = false;o.AutoTrackEntity = true;}).AddShardingTransaction((connection, builder) =>builder.UseSqlServer(connection)).AddDefaultDataSource("ds0", "Server=.;Database=TodoApp;Trusted_Connection=True").AddShardingTableRoute(o =>{o.AddShardingTableRoute<ToDoItemVirtualTableRoute>();}).End();}public override void OnPostApplicationInitialization(ApplicationInitializationContext context){context.ServiceProvider.GetRequiredService<IShardingBootstrapper>().Start();}稍微解釋下
options.Configure<TodoAppDbContext>(context1 =>{context1.DbContextOptions.UseSqlServer("Server=.;Database=TodoApp;Trusted_Connection=True").UseSharding<TodoAppDbContext>();});用來告訴abp,TodoAppDbContext的創建需要使用useSharding,
之后就是sharding-core默認提供的builder,當然你們可以自行封裝一下,別忘了在啟動的時候
這個千萬不能忘
運行TodoApp.Web
通過添加efcore的日志我們可以清晰地看到abp能夠正確的將對應的數據插入進去,并且完全不需要修改現有代碼,基本上的零基礎使用,簡單的配置,
如果您喜歡本庫就點點star點點贊,來都來了點個推薦不過分吧。為.net生態做一份貢獻,希望各位個多多提issue,和pr十分感激
項目demo
AbpVNextShardingTodoApp
總結
以上是生活随笔為你收集整理的Abp VNext 集成sharding-core 分表分库的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在业务层实现响应缓存
- 下一篇: 记一次 .NET 某资讯论坛 CPU爆高