本框架旨在爲EF Core提供Sharding(即讀寫分離分庫分表)支持,不只提供了一套強大的普通數據操做接口,而且下降了分表難度,支持按時間自動分表擴容,提供的操做接口簡潔統一.git
源碼地址:EFCore.SHardinggithub
讀寫分離分庫分表一直是數據庫領域中的重難點,當數據規模達到單庫極限的時候,就不得不考慮分表方案。EF Core做爲.NET Core中最爲主流的ORM,用起來十分方便快捷,可是官方並無相應的Sharding支持,鄙人不才,通過一番摸索以後終於完成這個框架.數據庫
首先根據須要安裝對應的Nuget包c#
包名 | 說明 |
---|---|
EFCore.Sharding | 必裝包,3.x版本對應EF Core3.x,2.x版本對應EF Core2.x |
EFCore.Sharding.MySql | MySql支持 |
EFCore.Sharding.PostgreSql | PostgreSql支持 |
EFCore.Sharding.SQLite | SQLite支持 |
EFCore.Sharding.SqlServer | SqlServer支持 |
EFCore.Sharding.Oracle | Oracle支持(暫不支持3.x) |
class Base_UnitTestShardingRule : ModShardingRule<Base_UnitTest> { protected override string KeyField => "Id"; protected override int Mod => 3; } ShardingConfig.Init(config => { config.AddAbsDb(DatabaseType.SQLite) .AddPhysicDb(ReadWriteType.Read | ReadWriteType.Write, "DataSource=db.db") .AddPhysicDbGroup() .AddPhysicTable<Base_UnitTest>("Base_UnitTest_0") .AddPhysicTable<Base_UnitTest>("Base_UnitTest_1") .AddPhysicTable<Base_UnitTest>("Base_UnitTest_2") .SetShardingRule(new Base_UnitTestShardingRule()); });
上述代碼中完成了Sharding配置框架
配置完成,下面開始使用,使用方式很是簡單,與日常使用基本一致
首先獲取分片倉儲接口IShardingRepositoryide
IShardingRepository _db = DbFactory.GetRepository().ToSharding();
而後便可進行數據操做:性能
Base_UnitTest _newData = new Base_UnitTest { Id = Guid.NewGuid().ToString(), UserId = "Admin", UserName = "超級管理員", Age = 22 }; List<Base_UnitTest> _insertList = new List<Base_UnitTest> { new Base_UnitTest { Id = Guid.NewGuid().ToString(), UserId = "Admin1", UserName = "超級管理員1", Age = 22 }, new Base_UnitTest { Id = Guid.NewGuid().ToString(), UserId = "Admin2", UserName = "超級管理員2", Age = 22 } }; //添加單條數據 _db.Insert(_newData); //添加多條數據 _db.Insert(_insertList); //清空表 _db.DeleteAll<Base_UnitTest>(); //刪除單條數據 _db.Delete(_newData); //刪除多條數據 _db.Delete(_insertList); //刪除指定數據 _db.Delete<Base_UnitTest>(x => x.UserId == "Admin2"); //更新單條數據 _db.Update(_newData); //更新多條數據 _db.Update(_insertList); //更新單條數據指定屬性 _db.UpdateAny(_newData, new List<string> { "UserName", "Age" }); //更新多條數據指定屬性 _db.UpdateAny(_insertList, new List<string> { "UserName", "Age" }); //更新指定條件數據 _db.UpdateWhere<Base_UnitTest>(x => x.UserId == "Admin", x => { x.UserId = "Admin2"; }); //GetList獲取表的全部數據 var list=_db.GetList<Base_UnitTest>(); //GetIQPagination獲取分頁後的數據 var list=_db.GetIShardingQueryable<Base_UnitTest>().GetPagination(pagination); //Max var max=_db.GetIShardingQueryable<Base_UnitTest>().Max(x => x.Age); //Min var min=_db.GetIShardingQueryable<Base_UnitTest>().Min(x => x.Age); //Average var min=_db.GetIShardingQueryable<Base_UnitTest>().Average(x => x.Age); //Count var min=_db.GetIShardingQueryable<Base_UnitTest>().Count(); //事務,使用方式與普通事務一致 bool succcess = _db.RunTransaction(() => { _db.Insert(_newData); var newData2 = _newData.DeepClone(); _db.Insert(newData2); }).Success; Assert.AreEqual(succcess, false);
上述操做中表面上是操做Base_UnitTest表,實際上卻在按照必定規則使用Base_UnitTest_0~2三張表,使分片對業務操做透明,極大提升開發效率
具體使用方式請參考單元測試源碼:鏈接單元測試
上面的哈希取模的方式雖然簡單,可是卻十分不實用,由於當3張分表到達瓶頸時,將會面臨擴容的問題,這種方式擴容須要進行大量的數據遷移,這無疑是十分麻煩的。所以須要一種方式可以系統自動建表擴容,而且無需人工干預,這就是按時間自動分表.學習
using Demo.Common; using EFCore.Sharding; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace Demo.AutoExpandByDate { class Base_UnitTestShardingRule : AbsShardingRule<Base_UnitTest> { public override DateTime BuildDate(Base_UnitTest obj) { return obj.CreateTime; } } class Program { /// <summary> /// 表都在同一個數據庫中 /// </summary> public static void OneGroup() { DateTime startTime = DateTime.Now.AddMinutes(-5); DateTime endTime = DateTime.MaxValue; //配置初始化 ShardingConfig.Init(config => { config.AddAbsDb(DatabaseType.SqlServer)//添加抽象數據庫 .AddPhysicDbGroup()//添加物理數據庫組 .AddPhysicDb(ReadWriteType.Read | ReadWriteType.Write, Config.ConString1)//添加物理數據庫1 .SetShardingRule(new Base_UnitTestShardingRule())//設置分表規則 .AutoExpandByDate<Base_UnitTest>(//設置爲按時間自動分表 ExpandByDateMode.PerMinute, (startTime, endTime, ShardingConfig.DefaultDbGourpName) ); }); var db = DbFactory.GetShardingRepository(); while (true) { db.Insert(new Base_UnitTest { Id = Guid.NewGuid().ToString(), Age = 1, UserName = Guid.NewGuid().ToString(), CreateTime = DateTime.Now }); var count = db.GetIShardingQueryable<Base_UnitTest>().Count(); Console.WriteLine($"當前數據量:{count}"); Thread.Sleep(50); } } /// <summary> /// 表分佈在兩個數據庫測試 /// </summary> public static void TwoGroup() { DateTime startTime1 = DateTime.Now.AddMinutes(-5); DateTime endTime1 = DateTime.Now.AddMinutes(5); DateTime startTime2 = endTime1; DateTime endTime2 = DateTime.MaxValue; string group1 = "group1"; string group2 = "group2"; //配置初始化 ShardingConfig.Init(config => { config.AddAbsDb(DatabaseType.SqlServer)//添加抽象數據庫 .AddPhysicDbGroup(group1)//添加物理數據庫組1 .AddPhysicDbGroup(group2)//添加物理數據庫組2 .AddPhysicDb(ReadWriteType.Read | ReadWriteType.Write, Config.ConString1, group1)//添加物理數據庫1 .AddPhysicDb(ReadWriteType.Read | ReadWriteType.Write, Config.ConString2, group2)//添加物理數據庫2 .SetShardingRule(new Base_UnitTestShardingRule())//設置分表規則 .AutoExpandByDate<Base_UnitTest>(//設置爲按時間自動分表 ExpandByDateMode.PerMinute, (startTime1, endTime1, group1), (startTime2, endTime2, group2) ); }); List<Task> tasks = new List<Task>(); for (int i = 0; i < 4; i++) { tasks.Add(Task.Run(() => { var db = DbFactory.GetShardingRepository(); while (true) { db.Insert(new Base_UnitTest { Id = Guid.NewGuid().ToString(), Age = 1, UserName = Guid.NewGuid().ToString(), CreateTime = DateTime.Now }); var count = db.GetIShardingQueryable<Base_UnitTest>().Count(); Console.WriteLine($"當前數據量:{count}"); Thread.Sleep(50); } })); } Console.ReadLine(); } static void Main(string[] args) { OneGroup(); Console.ReadLine(); } } }
上面Demo都在源碼中測試
上面的代碼實現了將Base_UnitTest表按照時間自動分表,每分鐘建立一張表,實際使用中根據業務需求設置ExpandByDateMode參數,經常使用按天、按月分表
自動分表效果
全程無需人工干預,系統會自動定時建立分表,十分簡單好用
using Demo.Common; using EFCore.Sharding; using System; using System.Diagnostics; using System.Linq; namespace Demo.Performance { class Base_UnitTestShardingRule : ModShardingRule<Base_UnitTest> { protected override string KeyField => "Id"; protected override int Mod => 3; } class Program { static void Main(string[] args) { ShardingConfig.Init(config => { config.AddAbsDb(DatabaseType.SqlServer) .AddPhysicDb(ReadWriteType.Read | ReadWriteType.Write, Config.ConString1) .AddPhysicDbGroup() .AddPhysicTable<Base_UnitTest>("Base_UnitTest_0") .AddPhysicTable<Base_UnitTest>("Base_UnitTest_1") .AddPhysicTable<Base_UnitTest>("Base_UnitTest_2") .SetShardingRule(new Base_UnitTestShardingRule()); }); var db = DbFactory.GetRepository(Config.ConString1, DatabaseType.SqlServer); Stopwatch watch = new Stopwatch(); var q = db.GetIQueryable<Base_UnitTest>() .Where(x => x.UserName.Contains("00001C22-8DD2-4D47-B500-407554B099AB")) .OrderByDescending(x => x.Id) .Skip(0) .Take(30); q.ToList(); q.ToSharding().ToList(); watch.Restart(); var list1 = q.ToList(); watch.Stop(); Console.WriteLine($"未分表耗時:{watch.ElapsedMilliseconds}ms"); watch.Restart(); var list2 = q.ToSharding().ToList(); watch.Stop(); Console.WriteLine($"分表後耗時:{watch.ElapsedMilliseconds}ms"); Console.WriteLine("完成"); } } }
分表Base_UnitTest_0-2各有100萬數據,而後將這三張表的數據導入Base_UnitTest中(即Base_UnitTest表的數據與Base_UnitTest_0-2三張表總合數據一致)
分表與不分表測試結果以下
這裏僅僅分了3張表,其效果立杆見影,若分表幾十張,那效果想一想就很棒
框架不只支持Sharing,並且封裝了經常使用數據庫操做,使用比較簡單
詳細使用方式參考 連接
這個簡單實用強大的框架但願可以幫助到你們,力求爲.NET生態貢獻一份力,你們一塊兒壯大.NET生態
歡迎使用本框架,若以爲不錯,請比心
Github歡迎星星:https://github.com/Coldairarrow
博客園歡迎點贊:https://www.cnblogs.com/coldairarrow/
QQ羣3:940069478
我的QQ:862520575(歡迎技術支持及商務合做,提供.NET Core + Linux + Nginx+ jenkins + git整套持續集成快速開發平臺)