<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文看懂.NET ORM 分表分庫!

          共 5162字,需瀏覽 11分鐘

           ·

          2020-10-13 03:03

          一、理論知識(shí)

          分表 - 從表面意思上看呢,就是把一張表分成N多個(gè)小表,每一個(gè)小表都是完正的一張表。分表后數(shù)據(jù)都是存放在分表里,總表只是一個(gè)外殼,存取數(shù)據(jù)發(fā)生在一個(gè)一個(gè)的分表里面。分表后單表的并發(fā)能力提高了,磁盤I/O性能也提高了。并發(fā)能力為什么提高了呢,因?yàn)椴閷ひ淮嗡ǖ臅r(shí)間變短了,如果出現(xiàn)高并發(fā)的話,總表可以根據(jù)不同 的查詢,將并發(fā)壓力分到不同的小表里面。

          分庫 - 把原本存儲(chǔ)于一個(gè)庫的數(shù)據(jù)分塊存儲(chǔ)到多個(gè)庫上,把原本存儲(chǔ)于一個(gè)表的數(shù)據(jù)分塊存儲(chǔ)到多個(gè)表上。數(shù)據(jù)庫中的數(shù)據(jù)量不一定是可控的,在未進(jìn)行分表分庫的情況下,隨著時(shí)間和業(yè)務(wù)的發(fā)展,庫中的表會(huì)越來越多,表中的數(shù)據(jù)量也會(huì)越來越大,相應(yīng)地,數(shù)據(jù)操作,增刪改查的開銷也會(huì)越來越大;另外,一臺(tái)服務(wù)器的資源(CPU、磁盤、內(nèi)存、IO等)是有限的,最終數(shù)據(jù)庫所能承載的數(shù)據(jù)量、數(shù)據(jù)處理能力都將遭遇瓶頸

          二、情懷滿滿

          分表、分庫在 .NET 下可謂是老大難題,簡單點(diǎn)可以使用類似 mycat 中間件,但是就 .NET 平臺(tái)的自身生態(tài),很缺乏類似 sharding-jdbc 這樣強(qiáng)大的輪子。

          本人就自身有限的技術(shù)水平和經(jīng)驗(yàn),對(duì)分表、分庫進(jìn)行分析,實(shí)現(xiàn)出自成一套的使用方法,雖然不極 sharding-jdbc 強(qiáng)大,但是還算比較通用、簡單。但愿有朝一日出現(xiàn)一批真正 .NET 大神,造出偉大的開源項(xiàng)目,實(shí)現(xiàn)你我心中的抱負(fù)。

          這套分表、分庫方法是建立在 .NET ORM FreeSql 之上做的,內(nèi)容可能比較抽象,敬請(qǐng)諒解!后續(xù)會(huì)詳解各種租戶設(shè)計(jì)方案,除了按字段區(qū)分租戶,還包括分庫、分表的方案,敬請(qǐng)關(guān)注!

          三、入戲準(zhǔn)備

          FreeSql 是 .Net ORM,能支持 .NetFramework4.0+、.NetCore、Xamarin、XAUI、Blazor、以及還有說不出來的運(yùn)行平臺(tái),因?yàn)榇a綠色無依賴,支持新平臺(tái)非常簡單。目前單元測試數(shù)量:5000+,Nuget下載數(shù)量:180K+,源碼幾乎每天都有提交。值得高興的是 FreeSql 加入了 ncc 開源社區(qū):https://github.com/dotnetcore/FreeSql,加入組織之后社區(qū)責(zé)任感更大,需要更努力做好品質(zhì),為開源社區(qū)出一份力。

          QQ群:4336577(已滿)、8578575(在線)、52508226(在線)

          為什么要重復(fù)造輪子?

          FreeSql 主要優(yōu)勢在于易用性上,基本是開箱即用,在不同數(shù)據(jù)庫之間切換兼容性比較好。作者花了大量的時(shí)間精力在這個(gè)項(xiàng)目,肯請(qǐng)您花半小時(shí)了解下項(xiàng)目,謝謝。功能特性如下:

          • 支持 CodeFirst 對(duì)比結(jié)構(gòu)變化遷移;
          • 支持 DbFirst 從數(shù)據(jù)庫導(dǎo)入實(shí)體類;
          • 支持 豐富的表達(dá)式函數(shù),自定義解析;
          • 支持 批量添加、批量更新、BulkCopy;
          • 支持 導(dǎo)航屬性,貪婪加載、延時(shí)加載、級(jí)聯(lián)保存;
          • 支持 讀寫分離、分表分庫,租戶設(shè)計(jì);
          • 支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite/達(dá)夢/神通/人大金倉/MsAccess;FreeSql 使用非常簡單,【單機(jī)數(shù)據(jù)庫】只需要定義一個(gè) IFreeSql 對(duì)象即可:
          static IFreeSql fsql = new FreeSql.FreeSqlBuilder()    .UseConnectionString(FreeSql.DataType.MySql, connectionString)    .UseAutoSyncStructure(true) //自動(dòng)同步實(shí)體結(jié)構(gòu)到數(shù)據(jù)庫    .Build(); //請(qǐng)務(wù)必定義成 Singleton 單例模式

          四、分表

          既然是分表,那就大膽認(rèn)為他是操作【單機(jī)數(shù)據(jù)庫】,只需要對(duì)實(shí)體類進(jìn)行動(dòng)態(tài)映射表名即可實(shí)現(xiàn),F(xiàn)reeSql 原生用法、FreeSql.Repository 倉儲(chǔ)用法 都提供了 AsTable 方法對(duì)分表進(jìn)行 CRUD 操作,例如:

          var repo = fsql.GetRepository();repo.AsTable(oldname => $"{oldname}_201903");//對(duì) Log_201903 表 CRUD
          repo.Insert(new Log { ... });repo.Update(...);repo.Delete(...);repo.Select...;

          AsTable 動(dòng)態(tài)設(shè)置實(shí)體映射的表名,達(dá)到對(duì)分表的操作目的。除了 CRUD 操作,還提供了創(chuàng)建分表的功能:

          • 如果開啟了自動(dòng)同步結(jié)構(gòu)功能 UseAutoSyncStructure(true),則 AsTable 會(huì)自動(dòng)創(chuàng)建對(duì)應(yīng)分表;
          • 可以使用 fsql.CodeFirst.SyncStructure(typeof(實(shí)體類), "分表名") 進(jìn)行手工建表;

          多數(shù)情況,我們都建議提前創(chuàng)建好分表,如果按月分表,手工創(chuàng)建一年的分表。目前這種算是比較簡單入門的方案,遠(yuǎn)不及 mycat、sharding-jdbc 那么智能,比如:

          • 不能利用分表字段自動(dòng)進(jìn)行分表映射;
          • 不能在查詢時(shí)根據(jù) where 條件自動(dòng)映射分表,甚至跨多個(gè)分表的聯(lián)合查詢;

          五、分庫(單機(jī))

          分庫,但是在同一個(gè)數(shù)據(jù)庫服務(wù)器實(shí)例下。這種情況也可以使用 AsTable 方式進(jìn)行操作,如下:

          var repo = fsql.GetRepository();repo.AsTable(oldname => $"{201903}.dbo.{oldname}");//對(duì) [201903].dbo.Log CRUD

          分庫之后,老大難題是事務(wù),如果使用 SqlServer 可以利用 TransactionScope 做簡單的跨庫事務(wù),如下:

          var repoLog = fsql.GetRepository();var repoComment = fsql.GetRepository();repoLog.AsTable(oldname => $"{201903}.dbo.{oldname}");repoComment.AsTable(oldname => $"{201903}.dbo.{oldname}");
          using (TransactionScope ts = new TransactionScope()){ repoComment.Insert(new Comment { ... }); repoLog.Insert(new Log { ... }); ts.Complete();}

          六、分庫(跨服務(wù)器)

          前面提到:【單機(jī)數(shù)據(jù)庫】只需要定義一個(gè) IFreeSql 對(duì)象即可。那分庫是不是要定義很多個(gè) IFreeSql 對(duì)象?答案是的。

          一般思路可以定義 static ConcurrentDictionary 存儲(chǔ)所有 IFreeSql 對(duì)象(key = ConnectionString),當(dāng)進(jìn)行 CRUD 時(shí)獲取到對(duì)應(yīng)的 IFreeSql 即可。由于 IFreeSql 是靜態(tài)單例設(shè)計(jì)長駐內(nèi)存,分庫數(shù)量太多的時(shí)候會(huì)浪費(fèi)資源,因?yàn)椴皇撬蟹謳於家恢币恢痹谠L問。例如租戶分庫 10000 個(gè),定義 10000 個(gè) static IFreeSql?

          更好的辦法可以使用 IdleBus 空閑對(duì)象管理容器,有效組織對(duì)象重復(fù)利用,自動(dòng)創(chuàng)建、銷毀,解決【實(shí)例】過多且長時(shí)間占用的問題。有時(shí)候想做一個(gè)單例對(duì)象重復(fù)使用提升性能,但是定義多了,有的又可能一直空閑著占用資源。專門解決:又想重復(fù)利用,又想少占資源的場景。https://github.com/2881099/IdleBus

          dotnet add package IdleBus

          static IdleBus ib = new IdleBus(TimeSpan.FromMinutes(10));
          ib.Register("db1", () => new FreeSqlBuilder().UseConnectionString(DataType.MySql, "str1").Build());ib.Register("db2", () => new FreeSqlBuilder().UseConnectionString(DataType.MySql, "str2").Build());ib.Register("db3", () => new FreeSqlBuilder().UseConnectionString(DataType.SqlServer, "str3").Build());//...注冊(cè)很多個(gè)
          ib.Get("db1").Select().Limit(10).ToList();

          IdleBus 也是【單例】設(shè)計(jì)!主要的兩個(gè)方法,注冊(cè),獲取。idlebus 注冊(cè)不是創(chuàng)建 IFreeSql,首次 Get 時(shí)才創(chuàng)建,后面會(huì)一直用已經(jīng)創(chuàng)建的。還有一個(gè)超時(shí)機(jī)制,如果 10 分鐘該 IFreeSql 未使用會(huì)被 Dispose,然后下一次又會(huì)創(chuàng)建新的 IFreeSql,如此反復(fù)。從而解決了 10000 個(gè) IFreeSql 長駐內(nèi)存的問題。

          還利用 AsyncLocal 特性擴(kuò)展使用起來更加方便:

          public static class IdleBusExtesions{    static AsyncLocal asyncDb = new AsyncLocal();    public static IdleBus ChangeDatabase(this IdleBus ib, string db)    {        asyncDb.Value = db;        return ib;    }    public static IFreeSql Get(this IdleBus ib) => ib.Get(asyncDb.Value ?? "db1");    public static IBaseRepository GetRepository(this IdleBus ib) where T : class         => ib.Get().GetRepository();}
          • 使用 ChangeDatabase 切換 db;
          • 使用 Get() 獲取當(dāng)前 IFreeSql,省略每次都傳遞 db 參數(shù);
          • 使用 GetRepository 獲取當(dāng)前 IFreeSql 對(duì)應(yīng)的倉儲(chǔ)類;

          注意:使用 IdleBus 需要弱化 IFreeSql 的存在,每次都使用 ib.Get 獲取 IFreeSql 對(duì)象;

          IdleBus ib = ...; //單例注入
          var fsql = ib.Get(); //獲取當(dāng)前租戶對(duì)應(yīng)的 IFreeSql
          var fsql00102 = ib.ChangeDatabase("db2").Get(); //切換租戶,后面的操作都是針對(duì) db2
          var songRepository = ib.GetRepository();var detailRepository = ib.GetRepository();

          目前這種算是比較簡單入門的方案,遠(yuǎn)不及 mycat、sharding-jdbc 那么智能,比如:沒有實(shí)現(xiàn)跨庫事務(wù)。

          七、寫在最后

          .NET 生態(tài)還處于較弱的狀態(tài),呼吁大家支持、踴躍參與開源項(xiàng)目,為下一個(gè) .NET 開源社區(qū)五年計(jì)劃做貢獻(xiàn)。

          希望正在使用的、善良的您能動(dòng)一動(dòng)小手指,把文章轉(zhuǎn)發(fā)一下,讓更多人知道 .NET 有這樣一個(gè)好用的 ORM 存在。謝謝了!!

          FreeSql 開源協(xié)議 MIT?

          https://github.com/dotnetcore/FreeSql

          可以商用,文檔齊全。

          QQ群:4336577(已滿)、8578575(在線)、52508226(在線)

          如果你有好的 ORM 實(shí)現(xiàn)想法,歡迎給作者留言討論,謝謝觀看!

          回復(fù)?【關(guān)閉】學(xué)關(guān)
          回復(fù)?【實(shí)戰(zhàn)】獲取20套實(shí)戰(zhàn)源碼
          回復(fù)?【被刪】學(xué)個(gè)
          回復(fù)?【訪客】學(xué)
          回復(fù)?【小程序】學(xué)獲取15套【入門+實(shí)戰(zhàn)+賺錢】小程序源碼
          回復(fù)?【python】學(xué)微獲取全套0基礎(chǔ)Python知識(shí)手冊(cè)
          回復(fù)?【2019】獲取2019 .NET 開發(fā)者峰會(huì)資料PPT
          回復(fù)?【加群】加入dotnet微信交流群

          強(qiáng)烈推薦:超全C#幫助類,提升效率就靠它


          瀏覽 37
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费高清不卡a无码 | 亚洲免费在线视频观看 | 国产一区 熟 | 欧美色图15p | 成人网站www污污污免费网站 |