FreeSql将Saas租户方案精简到极致[.NETORM]
什么是多租户维基百科:“软件多租户是指一种软件架构,在这种软件架构中,软件的一个实例运行在服务器上并且为多个租户服务”。一个租户是一组共享该软件实例特定权限的用户。有了多租户架构,软件应用被设计成为每个租户提供一个专用的实例包括该实例的数据的共享,还可以共享配置,用户管理,租户自己的功能和非功能属性。多租户和多实例架构相比,多租户分离了代表不同的租户操作的多个实例。
多租户用于创建Saas(Softwareas-aservice)应用(云处理)。
前言最近几乎每天38度,气温高于30度就不想面对电脑,虽然身体不愿意但依然坚持每天开机做支持,还好开源项目都比较稳定没那么多待解决问题,趁着暑假带着女儿学习游泳如今已变成小高手,现在正教她弟弟目前可游2米,相信10天左右应该也能学会吧。游泳好处太多了,建议有孩子的都去学学,我是在岸边指导大约一周左右就学会了,。
FreeSql有好几种实用功能,全局过滤器、对象值审计、分布式事务、分表,将这些功能组合使用,可以很方便的适应租户架构。其实FreeSql租户文档一直都有,只是内容没那么清淅(比较迷),既然FreeSqlbug少那就多优化一下文档吧!
本文讲解三种常用租户方案的实现,让使用者从此不再迷惑。如果你在使用其他更好的租户方案,欢迎加入讨论!
ORM概念ObjectRelationalMapping是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。
支持.+、.NetCore、Xamarin、MAUI、Blazor、以及还有说不出来的运行平台,因为代码绿色无依赖,支持新平台非常简单。目前单元测试数量:8500+,Nuget下载数量:1M+。
FreeSql使用最宽松的开源协议MIT,可以商用,文档齐全,甚至拿去卖钱也可以。
FreeSql主要优势在于易用性上,基本是开箱即用,在不同数据库之间切换兼容性比较好,整体的功能特性如下:
支持CodeFirst对比结构变化迁移;
支持DbFirst从数据库生成实体类;
支持丰富的表达式函数,独特的自定义解析;
支持批量添加、批量更新、BulkCopy;
支持导航属性,贪婪加载、延时加载、级联保存、级联删除;
支持读写分离、分表分库,租户设计,分布式事务;
支持MySql/SqlServer/PostgreSQL/Oracle/Sqlite/Firebird/达梦/神通/人大金仓/翰高/Clickhouse/实现包,以及Odbc的专门实现包;
8500+个单元测试作为基调,支持10多数数据库,我们提供了通用Odbc理论上支持所有数据库,目前已知有群友使用FreeSql操作华为高斯、mycat、tidb等数据库。安装时只需要选择对应的数据库实现包:
staticIFreeSqlfsql=().UseConnectionString(,@"DataSource=").UseAutoSyncStructure(true)//自动同步实体结构到数据库.UseNoneCommandParameter(true)//SQL不使用参数化,以便调试.UseMonitorCommand(cmd=())//打印();⚡方案一:按租户字段区分
此方案要求每个业务表包含TerantId字段,以便区分不同租户。假设当前租户值为1:
查询时自动附加条件whereTerantId=1
插入时自动赋值TerantId=1
更新时自动附加条件whereTerantId=1,防止修改其他租户的数据
删除时自动附加条件whereTerantId=1,防止删除其他租户的数据
FreeSql对此方案几乎可以做到0业务入侵,只需四步如下:
第1步:了解AsyncLocalint
ThreadLocal可以理解为字典Dictionaryint,stringKey=线程IDValue=值,跨方法时只需要知道线程ID,就能取得对应的Value。
我们知道跨异步方法可能造成线程ID变化,ThreadLocal将不能满足我们使用。
AsyncLocal是ThreadLocal的升级版,解决跨异步方法也能获取到对应的Value。
publicclassTerantManager{//注意一定是static静态化staticAsyncLocalint_asyncLocal=newAsyncLocalint();publicstaticintCurrent{get=_;set=_=value;}}第2步:FreeSql全局过滤器,让任何查询/更新/删除,都附带租户条件;
以下代码若当前没有设置租户值,则过滤器不生效,什么意思?
//全局过滤器只需要在IFreeSql初始化处执行一次//ITerant可以是自定义接口,也可以是任何一个包含TerantId属性的实体类型,FreeSql不需要为每个实体类型都设置过滤器(一次即可)("TerantFilter",//过滤器名称()=,//过滤器生效判断a===//过滤器条件);=0;().ToList();//SELECT..=1;().ToList();//SELECT..FROMTWHERETerantId=1第3步:对象审计事件,实现统一拦截插入、更新实体对象;
+=(_,e)={if(==typeof(int)=="TerantId"){=}};第4步:中间件处理租户逻辑;
publicvoidConfigure(IApplicationBuilderapp){(async(context,next)={try{//使用者通过aspnetcore中间件,解析token获得租户=YourGetTerantIdFunction();awaitnext();}finally{//清除租户状态=0;}});();(a=());}方案二:按租户分表此方案要求每个租户对应不同的数据表,如Goods_1、Goods_2、Goods_3分别对应租户1、租户2、租户3的商品表。
这其实就是一般的分表方案,FreeSql提供了分表场景的几个API:
创建表(typeof(Goods),"Goods_1")
操作表CURD
vargoodsRepository=(null,old=#34;{Goods}_{}");上面我们得到一个仓储按租户分表,使用它CURD最终会操作Goods_1表。
方案三:按租户分库场景1:同数据库实例(未跨服务器),租户间使用不同的数据库名或Schema区分,使用方法与方案二相同;
场景2:跨服务器分库,本段讲解该场景;
第1步:为FreeSql提供跨数据库访问,分布式事务TCC、SAGA解决方案,支持.+,.+.
原本使用FreeSqlBuilder创建IFreeSql,需要使用FreeSqlCloud代替,因为FreeSqlCloud也实现了IFreeSql接口。
or
FreeSqlCloudstringfsql=newFreeSqlCloudstring();publicvoidConfigureServices(IServiceCollectionservices){=log=(('\n')[0].Trim());("main",()={vardb=newFreeSqlBuilder().UseConnectionString(,"datasource=").Build();//+=可设置事件打印SQLreturndb;});(fsql);();}publicvoidConfigure(IApplicationBuilderapp,IWebHostEnvironmentenv){(async(context,next)={try{//使用者通过aspnetcore中间件,解析token,查询main库得到租户信息。(stringterant,stringconnectionString)=YourGetTerantFunction();//只会首次注册,如果已经注册过则不生效(terant,()={vardb=newFreeSqlBuilder().UseConnectionString(,connectionString).Build();//+=可设置事件打印SQLreturndb;});//切换租户(terant);awaitnext();}finally{//切换回main库("main");}});();(a=());}第2步:直接使用IFreeSql访问租户数据库
publicclassHomeController:ControllerBase{[HttpGet]publicobjectGet([FromServices]IFreeSqlfsql){//使用fsql操作当前租户对应的数据库,也可以使用("main")操作main数据库。return"";}}这样的跨库租户你喜欢吗,对原先我使用IFreeSql开发的单体项目,几乎0业务入侵。
我们甚至可以做到只针对某几个实体类弄,才切换到对应的租户数据库。
⛳结束语FreeSql的稳定性,以及可扩展性,我不想吹牛,也不喜欢吹牛,如果大家有什么好的想法可以一起讨论,毕竟我只是一个个体,还有很多我不知道的场景不是吗?
希望这篇文章能帮助大家轻松理解并熟练掌握它,快速上手开发Saas租户应用项目,为企业的项目研发贡献力量。
开源地址:
FreeSql作者是什么人?
FreeSql作者是一个入行18年的老批,他目前写的.net开源项目有:
开源项目
描述
开源地址
开源协议
ImCore
架构最简单,扩展性最强的聊天系统架构
最宽松的MIT协议,可商用
FreeRedis
最简单的RediscClient
最宽松的MIT协议,可商用
csredis
最宽松的MIT协议,可商用
FightLandlord
斗地主单机或网络版
最宽松的MIT协议,学习用途
FreeScheduler
定时任务
最宽松的MIT协议,可商用
IdleBus
空闲容器
最宽松的MIT协议,可商用
FreeSql
国产最好用的ORM
最宽松的MIT协议,可商用
分布式事务tcc/saga
最宽松的MIT协议,可商用
低代码后台管理项目生成
最宽松的MIT协议,可商用
动态代理
最宽松的MIT协议,学习用途
需要的请拿走,这些都是最近几年的开源作品,以前更早写的就不发了。





