Abp VNext 分表分库ShardingCore(分库分表查询排序)
ccwgpt 2024-09-20 13:35 23 浏览 0 评论
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> options
ShardingCoreHelper.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,是自动创建的guid
public interface IShardingKeyIsGuId
{
}
//标识对应的分表对应的分表字段是创建时间
public interface IShardingKeyIsCreationTime
{
}
//修改TodoItem
public 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
static TodoAppDbContextFactory()
{
var services = new ServiceCollection();
var configuration = BuildConfiguration();
services.AddShardingDbContext<TodoAppDbContext>(
(conn, o) =>
o.UseSqlServer(conn)
.ReplaceService<IMigrationsSqlGenerator, ShardingSqlServerMigrationsSqlGenerator<TodoAppDbContext>>()
).Begin(o =>
{
o.AutoTrackEntity = true;
})
.AddShardingTransaction((connection, builder) =>
builder.UseSqlServer(connection))
.AddDefaultDataSource("ds0",
configuration.GetConnectionString("Default"))
.AddShardingTableRoute(o =>
{
o.AddShardingTableRoute<ToDoItemVirtualTableRoute>();
}).End();
services.AddLogging();
var buildServiceProvider = services.BuildServiceProvider();
ShardingContainer.SetServices(buildServiceProvider);
new ShardingBootstrapper(buildServiceProvider).Start();
}
public TodoAppDbContext CreateDbContext(string[] args)
{
return ShardingContainer.GetService<TodoAppDbContext>();
}
主要代码就是告诉efcore.tools如何创建对应的dbcontext
然后打开nuget控制台
选中需要生成迁移的项目
启动项设置为
执行命令
PM> Add-Migration InitTodoApp
PM> 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,当然你们可以自行封装一下,别忘了在启动的时候
context.ServiceProvider.GetRequiredService<IShardingBootstrapper>().Start();
这个千万不能忘
运行TodoApp.Web
通过添加efcore的日志我们可以清晰地看到abp能够正确的将对应的数据插入进去,并且完全不需要修改现有代码,基本上的零基础使用,简单的配置,
如果您喜欢本库就点点star点点赞,来都来了点个推荐不过分吧。为.net生态做一份贡献,希望各位个多多提issue,和pr十分感激
相关推荐
- Spring WebFlux vs. Spring MVC(springboot是什么)
-
背景随着异步I/O和Netty等框架的流行,响应式编程逐渐走入大众的视野。但是,响应式编程本身并不是太新的概念,这个术语最早出现在1985年DavidHarel和AmirPnue...
- 深度解析微服务高并发:适配SpringMVC框架适配模块及实现原理
-
适配主流框架如果不借助Sentinel提供的适配主流框架的模块,则在使用Sentinel时需要借助try-catchfinally将要保护的资源(方法或代码块)包起来,在目标方法或代码块执行之前,调...
- Spring MVC 底层原理深度解析:从请求到响应的全链路拆解
-
一、Servlet容器与DispatcherServlet的启动博弈1.Tomcat初始化阶段java//Tomcat初始化流程StandardContext#startInterna...
- 改造总结之传统SpringMVC架构转换为SpringBoot再到集群
-
改造出发点,是基于现在服务都在向上云的目标前进,传统SpringMVC难以满足项目持续构建、服务节点任意扩展的需求,所以开始了历史项目的改造。项目改造考虑的主要是兼容以前的业务代码,以及session...
- SpringBoot3 整合 Spring MVC 全解析:开启高效 Web 开发之旅
-
在当今的JavaWeb开发领域,Spring框架家族无疑占据着重要的地位。其中,SpringBoot3和SpringMVC更是开发者们构建强大、高效Web应用的得力工具。今天,...
- 一文读懂SpringMVC(一文读懂!残疾人低保边缘家庭能领的超实用福利政策)
-
1.SpringMVC定义1.1.MVC定义Model(模型):是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据View(视图):是应用程序中处理数据显示的部分。通常...
- 69 个Spring mvc 全部注解:真实业务使用案例说明(必须收藏)
-
SpringMVC框架的注解为Web开发提供了一种简洁而强大的声明式方法。从控制器的定义、请求映射、参数绑定到异常处理和响应构建,这些注解涵盖了Web应用程序开发的各个方面。它们不仅简化了编码工作,...
- Spring MVC工作原理:像拼积木一样构建Web应用
-
SpringMVC工作原理:像拼积木一样构建Web应用在Java的Web开发领域,SpringMVC无疑是一个让人又爱又恨的存在。它像一位神通广大的积木搭建大师,将一个个分散的功能模块巧妙地拼接在...
- 5千字的SpringMVC总结,我觉得你会需要
-
思维导图文章已收录到我的Github精选,欢迎Star:https://github.com/yehongzhi/learningSummary概述SpringMVC再熟悉不过的框架了,因为现在最火的...
- SpringMVC工作原理与优化指南(springmvc工作原理和工作流程)
-
SpringMVC工作原理与优化指南在现代Java开发中,SpringMVC无疑是构建Web应用程序的首选框架之一。它以其优雅的设计和强大的功能吸引了无数开发者。那么,SpringMVC究竟是如何工作...
- Spring MVC框架源码深度剖析:从入门到精通
-
SpringMVC框架源码深度剖析:从入门到精通SpringMVC框架简介SpringMVC作为Spring框架的一部分,为构建Web应用程序提供了强大且灵活的支持。它遵循MVC(Model-V...
- 3000字搞明白SpringMVC工作流程、DispatcherServlet类、拦截器!
-
SpringMVC基础虽然SpringBoot近几年发展迅猛,但是SpringMVC在Web开发领域仍然占有重要的地位。本章主要讲解SpringMVC的核心:DispatcherServlet类...
- 多年经验大佬用2000字透彻解析SpringMVC的常用注解及相关示例
-
SpringMVC注解SpringMVC框架提供了大量的注解,如请求注解、参数注解、响应注解及跨域注解等。这些注解提供了解决HTTP请求的方案。本节主要讲解SpringMVC的常用注解及相关示例...
- 知乎热议:如何成为前端架构师,赚百万年薪?
-
作者|慕课网精英讲师双越最近有一条知乎热议:从一个前端工程师,如何根据目标,制定计划,才能快速进阶成为前端架构师?不久之前我参与了一次直播,讲到了自己对于Web前端架构师的理解。架构师这个角色...
- 学习笔记-前端开发架构设计(前端架构设计方案)
-
前端开发的技术选项主要包含以下几点,下面对一些名词概念的解释做了笔记:1、分层架构:把功能相似,抽象级别相近的实现进行分层隔离优势:松散耦合(易维护,易复用,易扩展)常见分层方式:MVC,MVVM2、...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- Spring WebFlux vs. Spring MVC(springboot是什么)
- 深度解析微服务高并发:适配SpringMVC框架适配模块及实现原理
- Spring MVC 底层原理深度解析:从请求到响应的全链路拆解
- 改造总结之传统SpringMVC架构转换为SpringBoot再到集群
- SpringBoot3 整合 Spring MVC 全解析:开启高效 Web 开发之旅
- 一文读懂SpringMVC(一文读懂!残疾人低保边缘家庭能领的超实用福利政策)
- 69 个Spring mvc 全部注解:真实业务使用案例说明(必须收藏)
- Spring MVC工作原理:像拼积木一样构建Web应用
- 5千字的SpringMVC总结,我觉得你会需要
- SpringMVC工作原理与优化指南(springmvc工作原理和工作流程)
- 标签列表
-
- MVC框架 (46)
- spring框架 (46)
- 框架图 (58)
- bootstrap框架 (43)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- laravel框架 (46)
- express框架 (43)
- springmvc框架 (49)
- scrapy框架 (52)
- beego框架 (42)
- java框架spring (43)
- grpc框架 (55)
- orm框架有哪些 (43)
- ppt框架 (48)
- 内联框架 (52)
- winform框架 (46)
- gui框架 (44)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)
- oracle提交事务 (47)