基于efcore的分表组件开源
ShardingCore
ShardingCore 是一个支持efcore 2.x 3.x 5.x的一个对于数据库分表的一个简易扩展,
目前该库暂未支持分库(未来会支持),仅支持分表,该项目的理念是让你可以已最少的代码量来实现自动分表的实现,经过多个开源项目的摸索参考目前正式开源本项目
项目地址 github 喜欢的朋友可以点下star Thanks♪(・ω・)ノ
依赖
| Release | EF Core | .NET Standard | .NET (Core) | Sql Server | Pomelo.EntityFrameworkCore.MySql |
|---|---|---|---|---|---|
| 5.x.x.x | >= 5.0.x | 2.1 | 3.0+ | >= 2012 | 5.0.0-alpha.2 |
| 3.x.x.x | 3.1.10 | 2.0 | 2.0+ | >= 2012 | 3.2.4 |
| 2.x.x.x | 2.2.6 | 2.0 | 2.0+ | >= 2008 | 2.2.6 |
开始
以下所有例子都以Sql Server为例 MySql亦如此
简介
目前该库处于初期阶段,有很多bug也希望各位多多理解,一起努力为.net生态做出一份微薄之力,目前该库支持的分页可以进行完全的自定义,基本上可以满足95%以上的
业务需求,唯一的限制就是分表规则必须满足 x+y+z,x表示固定的表名,y表示固定的表名和表后缀之间的联系(可以为空),z表示表后缀,可以按照你自己的任意业务逻辑进行切分,
如:user_0,user_1或者user202101,user202102...当然该库同样适用于多租户模式下的隔离,该库为了支持之后的分库已经重写了之前的union all查询模式,并且支持多种api,
支持多种查询包括join group by max count min avg sum ...等一系列查询,之后可能会添加更多支持,目前该库的使用非常简单,基本上就是针对IQueryable的扩展,为了保证
该库的简介目前仅使用该库无法或者说难以实现自动建表,但是只需要配合定时任务该库即可完成24小时无人看管自动管理。该库提供了 IShardingTableCreator
作为建表的依赖,如果需要可以参考 按天自动建表
概念
本库的几个简单的核心概念:
- [Tail]
尾巴、后缀物理表的后缀 - [TailPrefix]
尾巴前缀虚拟表和物理表的后缀中间的字符 - [物理表]
顾名思义就是数据库对应的实际表信息,表名(tablename+ tailprefix+ tail) IPhysicTable - [虚拟表]
虚拟表就是系统将所有的物理表在系统里面进行抽象的一个总表对应到程序就是一个entityIVirtualTable - [虚拟路由]
虚拟路由就是联系虚拟表和物理表的中间介质,虚拟表在整个程序中只有一份,那么程序如何知道要查询系统哪一张表呢,最简单的方式就是通过虚拟表对应的路由IVirtualRoute
,由于基本上所有的路由都是和业务逻辑相关的所以虚拟路由由用户自己实现,该框架提供一个高级抽象
优点
- [支持自定义分表规则]
- [支持任意类型分表key]
- [针对iqueryable的扩展方便使用]
- [支持分表下的连表]
join - [支持针对批处理的使用]
BulkInsert、BulkUpdate、BulkDelete - [提供多种默认分表规则路由] 按时间按取模
- [针对分页进行优化] 大页数跳转支持低内存流式处理
缺点
- [暂不支持分库(不久后会支持)]
- [消耗连接]出现分表与分表对象进行join如果条件没法索引到具体表会生成
笛卡尔积导致连接数爆炸,后期会进行针对该情况的配置 - [该库比较年轻] 可能会有一系列bug或者单元测试不到位的情况,但是只要你在群里或者提了issues我会尽快解决
安装
<PackageReference Include="ShardingCore.SqlServer" Version="5.0.0.3" />
配置
配置entity 推荐 fluent api 可以实现自动建表功能
IShardingEntity数据库对象必须继承该接口
ShardingKey分表字段需要使用该特性
public class SysUserMod:IShardingEntity
{
/// <summary>
/// 用户Id用于分表
/// </summary>
[ShardingKey]
public string Id { get; set; }
/// <summary>
/// 用户名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 用户姓名
/// </summary>
public int Age { get; set; }
}
public class SysUserModMap:IEntityTypeConfiguration<SysUserMod>
{
public void Configure(EntityTypeBuilder<SysUserMod> builder)
{
builder.HasKey(o => o.Id);
builder.Property(o => o.Id).IsRequired().HasMaxLength(128);
builder.Property(o => o.Name).HasMaxLength(128);
builder.ToTable(nameof(SysUserMod));
}
}
创建virtual route
实现 AbstractShardingOperatorVirtualRoute<T, TKey>
抽象,或者实现系统默认的虚拟路由
框架默认有提供几个简单的路由 默认路由
public class SysUserModVirtualRoute : AbstractSimpleShardingModKeyStringVirtualRoute<SysUserMod>
{
public SysUserModVirtualRoute() : base(3)
{
}
public override List<string> GetAllTails()
{
return new() { "0","1","2"};
}
}
GetAllTails
现在数据库已存在的尾巴有哪些
Startup.cs 下的 ConfigureServices(IServiceCollection services)
services.AddShardingSqlServer(o =>
{
o.ConnectionString = "";
o.AddSharding<SysUserModVirtualRoute>();
o.UseShardingCoreConfig((provider, config) =>
{
//如果是development就判断并且新建数据库如果不存在的话(ishardingentity不会被创建)
config.EnsureCreated = provider.GetService<IHostEnvironment>().IsDevelopment();
//ishardingentity表是否需要在启动时创建(如果已创建可以选择不创建)
config.CreateShardingTableOnStart = true;
});
});
Startup.cs 下的 Configure(IApplicationBuilder app, IWebHostEnvironment env) 你也可以自行封装app.UseShardingCore()
var shardingBootstrapper = app.ApplicationServices.GetRequiredService<IShardingBootstrapper>();
shardingBootstrapper.Start();
使用
private readonly IVirtualDbContext _virtualDbContext;
public ctor(IVirtualDbContext virtualDbContext)
{
_virtualDbContext = virtualDbContext;
}
public async Task ToList_All()
{
//查询list集合
var all=await _virtualDbContext.Set<SysUserMod>().ToShardingListAsync();
//链接查询
var list = await (from u in _virtualDbContext.Set<SysUserMod>()
join salary in _virtualDbContext.Set<SysUserSalary>()
on u.Id equals salary.UserId
select new
{
Salary = salary.Salary,
DateOfMonth = salary.DateOfMonth,
Name = u.Name
}).ToShardingListAsync();
//聚合查询
var ids = new[] {"200", "300"};
var dateOfMonths = new[] {202111, 202110};
var group = await (from u in _virtualDbContext.Set<SysUserSalary>()
.Where(o => ids.Contains(o.UserId) && dateOfMonths.Contains(o.DateOfMonth))
group u by new
{
UId = u.UserId
}
into g
select new
{
GroupUserId = g.Key.UId,
Count = g.Count(),
TotalSalary = g.Sum(o => o.Salary),
AvgSalary = g.Average(o => o.Salary),
MinSalary = g.Min(o => o.Salary),
MaxSalary = g.Max(o => o.Salary)
}).ToShardingListAsync();
}
更多操作可以参考单元测试
Api
| 方法 | Method | SqlServer Unit Test | MySql Unit Test |
|---|---|---|---|
| 获取集合 | ToShardingListAsync | yes | yes |
| 第一条 | ShardingFirstOrDefaultAsync | yes | yes |
| 最大 | ShardingMaxAsync | yes | yes |
| 最小 | ShardingMinAsync | yes | yes |
| 是否存在 | ShardingAnyAsync | yes | yes |
| 分页 | ToShardingPageResultAsync | yes | yes |
| 数目 | ShardingCountAsync | yes | yes |
| 求和 | ShardingSumAsync | yes | yes |
| 分组 | ShardingGroupByAsync | yes | yes |
默认路由
| 抽象abstract | 路由规则 | tail | 索引 |
|---|---|---|---|
| AbstractSimpleShardingModKeyIntVirtualRoute | 取模 | 0,1,2... | = |
| AbstractSimpleShardingModKeyStringVirtualRoute | 取模 | 0,1,2... | = |
| AbstractSimpleShardingDayKeyDateTimeVirtualRoute | 按时间 | yyyyMMdd | >,>=,<,<=,=,contains |
| AbstractSimpleShardingDayKeyLongVirtualRoute | 按时间戳 | yyyyMMdd | >,>=,<,<=,=,contains |
| AbstractSimpleShardingWeekKeyDateTimeVirtualRoute | 按时间 | yyyyMMdd_dd | >,>=,<,<=,=,contains |
| AbstractSimpleShardingWeekKeyLongVirtualRoute | 按时间戳 | yyyyMMdd_dd | >,>=,<,<=,=,contains |
| AbstractSimpleShardingMonthKeyDateTimeVirtualRoute | 按时间 | yyyyMM | >,>=,<,<=,=,contains |
| AbstractSimpleShardingMonthKeyLongVirtualRoute | 按时间戳 | yyyyMM | >,>=,<,<=,=,contains |
| AbstractSimpleShardingYearKeyDateTimeVirtualRoute | 按时间 | yyyy | >,>=,<,<=,=,contains |
| AbstractSimpleShardingYearKeyLongVirtualRoute | 按时间戳 | yyyy | >,>=,<,<=,=,contains |
注:contains表示为o=>ids.contains(o.shardingkey)
高级
批量操作
批量操作将对应的dbcontext和数据进行分离由用户自己选择第三方框架比如zzz进行批量操作或者batchextension
virtualDbContext.BulkInsert<SysUserMod>(new List<SysUserMod>())
.BatchGroups.ForEach(pair =>
{
///zzz or other
pair.Key.BlukInsert(pair.Value);
});
var shardingBatchUpdateEntry = virtualDbContext.BulkUpdate<SysUserMod>(o => o.Id == "1", o => new SysUserMod()
{
Name = "name_01"
});
shardingBatchUpdateEntry.DbContexts.ForEach(context =>
{
//zzz or other
context.Where(shardingBatchUpdateEntry.Where).Update(shardingBatchUpdateEntry.UpdateExp);
});
手动路由
var shardingQueryable = _virtualDbContext.Set<SysUserMod>().AsSharding();
//禁用自动路由
shardingQueryable.DisableAutoRouteParse();
//添加路由直接查询尾巴0的表
shardingQueryable.AddManualRoute<SysUserMod>("0");
//添加路由针对该条件的路由
shardingQueryable.AddManualRoute<SysUserMod>(o=>o.Id=="100");
var list=await shardingQueryable.ToListAsync();
自动建表
事务
默认savechanges支持事务如果需要where.update需要手动开启事务
_virtualDbContext.BeginTransaction();
var shardingBatchUpdateEntry = _virtualDbContext.BulkUpdate<SysUserMod>(o=>o.Id=="123",o=>new SysUserMod()
{
Name = "name_modify"
});
foreach (var dbContext in shardingBatchUpdateEntry.DbContexts)
{
//zzz or other batch
}
await _virtualDbContext.SaveChangesAsync();
注意事项
该库的IVirtualDbContext.Set使用asnotracking所以基本不支持跟踪,目前框架采用AppDomain.CurrentDomain.GetAssemblies();
可能会导致程序集未被加载所以尽可能在api层加载所需要的dll
计划
- [提供官网如果该项目比较成功的话]
- [开发更完善的文档]
- [支持分库]
- [支持更多数据库查询]
最后
理论上该库的思想可以解决大部分orm的分表,目前是仅针对efcore的后期如果可以获取也会对其他orm进行sharding库的开发
该框架借鉴了大部分分表组件的思路,目前提供的接口都已经实现,并且支持跨表查询,基于分页查询该框架也使用了流式查询保证不会再skip大数据的时候内存会爆炸,至于groupby目前已经在开发支持了,相信不久后就会发布新版本,目前这个库只是一个刚刚成型的库还有很多不完善的地方希望大家多多包涵,如果喜欢的话也希望大家给个star.
该文档是我晚上赶工赶出来的也想趁热打铁希望更多的人关注,也希望更多的人可以交流。
凭借各大开源生态圈提供的优秀代码和思路才有的这个框架,希望可以为.Net生态提供一份微薄之力,该框架本人会一直长期维护,有大神技术支持可以联系下方方式欢迎star
QQ群:771630778
个人QQ:326308290(欢迎技术支持提供您宝贵的意见)
个人邮箱:326308290@qq.com
基于efcore的分表组件开源的更多相关文章
- .NET 5 全自动分表组件,.NET 分表方案 ,分表架构与设计
一.疑问&目的 1.1 分表使用场景 (1)可扩展架构设计,比如一个ERP用5年不卡,到了10就卡了因为数据太多了,这个时候很多人都是备份然后清空数据,这个工作大并且麻烦,以前的数据很难在使用 ...
- 架构组件:基于Shard-Jdbc分库分表,数据库扩容方案
本文源码:GitHub·点这里 || GitEE·点这里 一.数据库扩容 1.业务场景 互联网项目中有很多"数据量大,业务复杂度高,需要分库分表"的业务场景. 这样分层的架构 (1 ...
- Spring-boot2X基于sharding-jdbc3.x分表分库
ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC.Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的 ...
- 数据量大了一定要分表,分库分表组件Sharding-JDBC入门与项目实战
最近项目中不少表的数据量越来越大,并且导致了一些数据库的性能问题.因此想借助一些分库分表的中间件,实现自动化分库分表实现.调研下来,发现Sharding-JDBC目前成熟度最高并且应用最广的Java分 ...
- TSharding:用于蘑菇街交易平台的分库分表组件
tsharding TSharding is the simple sharding component used in mogujie trade platform. 分库分表业界方案 分库分表TS ...
- efcore分表下"完美"实现
ShardingCore 如何呈现"完美"分表 这篇文章是我针对efcore的分表的简单介绍,如果您有以下需求那么可以自己选择是否使用本框架,本框架将一直持续更新下去,并且免费开源 ...
- efcore分表分库原理解析
ShardingCore ShardingCore 易用.简单.高性能.普适性,是一款扩展针对efcore生态下的分表分库的扩展解决方案,支持efcore2+的所有版本,支持efcore2+的所有数据 ...
- 基于SpringCloud实现Shard-Jdbc的分库分表模式,数据库扩容方案
本文源码:GitHub·点这里 || GitEE·点这里 一.项目结构 1.工程结构 2.模块命名 shard-common-entity: 公共代码块 shard-open-inte: 开放接口管理 ...
- mysql、oracle分库分表方案之sharding-jdbc使用(非demo示例)
选择开源核心组件的一个非常重要的考虑通常是社区活跃性,一旦项目团队无法进行自己后续维护和扩展的情况下更是如此. 至于为什么选择sharding-jdbc而不是Mycat,可以参考知乎讨论帖子https ...
随机推荐
- 如何使用Pycharm在网页上展示诗歌。(HTML)
!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"&g ...
- String、StringBuffer 和 StringBuilder 的区别
面试简答 区别: 1) String 长度大小不可变 2) StringBuffer 和 StringBuilder 长度可变 3) StringBuffer 线程安全 StringBuilder 线 ...
- vue-vite浅析
大家好,我是小雨小雨,致力于分享有趣的.实用的文章. 内容分为原创和翻译,如果有问题,欢迎随时评论或私信,很乐意和大家一起探讨,一起进步. 分享不易,希望能够得到大家的支持和关注. vite出了好久了 ...
- CTF常见编码及加解密(超全)
@ 目录 前言 常见CTF编码及加解密 补充 ASCII编码 base家族编码 MD5.SHA1.HMAC.NTLM等类似加密型 1.MD5 2.SHA1 3.HMAC 4.NTLM 5.类似加密穷举 ...
- Java安全之RMI协议分析
Java安全之RMI协议分析 0x00 前言 在前面其实有讲到过RMI,但是只是简单描述了一下RMI反序列化漏洞的利用.但是RMI底层的实现以及原理等方面并没有去涉及到,以及RMI的各种攻击方式.在其 ...
- self-taught CS resouce recommendation
https://github.com/keithnull/TeachYourselfCS-CN/blob/master/TeachYourselfCS-CN.md#%E8%AE%A1%E7%AE%97 ...
- 【RAC】10grac添加节点,详细步骤
RAC物理结构 现在的RAC环境是二个节点: dbp,dbs, 这个实验就是添加节点dbi. dbp,dbs和dbi节点的信息规划如下: 服务器主机名 dbp dbs dbi 公共IP地址(eth0) ...
- 原生js制作表单验证,基本的表单验证方法
表单验证是web前端最常见的功能之一,也属于前端开发的基本功.自己完成一个表单验证的开发,也有助于加深对字符串处理和正则表达式的理解. 基本的表单验证包括如:字母验证.数字验证.字母和数字验证.汉字验 ...
- Core3.1 微信v3 JSAPI支付
1.前言 "小魏呀,这个微信支付还要多久?","快了快了老板,就等着最后一步了...","搞快点哈,就等着上线呢","...... ...
- 安装git-macOS系统
通过homebrew安装Git 1.安装homebrew /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/H ...