Colder框架硬核更新(Sharding+IOC)

来源:https://www.cnblogs.com/coldairarrow/archive/2019/06/24/11075037.html
-Advertisement-
Play Games

目錄 "引言" "控制反轉" "讀寫分離分庫分表" "理論基礎" "設計目標" "現狀調研" "設計思路" "實現之過五關斬六將" "動態對象" "動態模型緩存" "數據源移植" "查詢表達式樹深度移植" "數據合併演算法" "事務支持" "實際使用" "展望未來" 引言 前方硬核警告:全文乾貨110 ...


目錄

引言

前方硬核警告:全文乾貨11000+字,請耐心閱讀
遙想去年這個時候,差不多剛剛畢業,如今正式工作差不多一年了。Colder開源快速開發框架從上次版本發佈至今差不多有三個月了,Github的星星5個版本框架總共也有近800顆,QQ群從最初的一個人發展到現在的500人(吐槽下,人數上限了,太窮開不起SVIP,所以另開了一個,群號在文章末),這都是大家共同發展的結果,本框架能夠幫助到大家鄙人就十分開心。但是,技術是不斷發展的,本框架也必須適應潮流,不斷升級才能夠與時俱進,在實際意義上提高生產力。本系列框架從原始雛形(鄙人畢業設計)=>.NET45+Easyui=>.NET Core2.1+Easyui=>.NET45+AdminLTE=>.NET Core2.1+AdminLTE,這其中都是根據實際情況不斷升級。例如鄙人最初的畢業設計搭建了框架的雛形(倉儲層不夠完善、界面較簡陋),並不適合實際的生產開發,因此使用Easyui作為前端UI框架(控制項豐富,使用簡單),後又由於.NET Core的發展迅速,已經發展到2.0,其基礎類庫組件也相對比較成熟了,因此從.NET45遷移到.NET Core。後來發現Easyui的樣式比較落後,給人一種過時古老的感覺,故而又將前端UI改為基於Bootstrap的AdminLTE,比較成熟主流並且開源。
但是,新的要求又出現了:

  • 由於沒有使用IOC導致各個類通過New導致的強耦合問題
  • 資料庫大數據量如何處理的問題
    因此,本次版本更新主要就是為瞭解決上述的問題,即全面使用Autofac作為IOC容器實現解耦以及資料庫讀寫分離分庫分表(Sharding)支持。下麵將分別介紹。
    這次更新.NET45版本與.NET Core版本同步更新:
.NET版本 前端UI 地址
Core2.2 AdminLTE https://github.com/Coldairarrow/Colder.Fx.Core.AdminLTE
.NET4.52 AdminLTE https://github.com/Coldairarrow/Colder.Fx.Net.AdminLTE

控制反轉

IOC(DI),即控制反轉(依賴註入),相關概念大家應該都知道,並且大多數人應該都已經運用於實際。我就簡單描述下,簡單講就是面向介面編程,通過介面來解除類之間的強耦合,方便開發維護測試。這個概念在JAVA開發中應該比較普遍,因為有Spring框架的正確引導,但是在.NET中可能開發人員的相關意識就沒那麼強,JAVA與.NET我這裡不做評價,但是作為技術人員,天生就是不斷學習的,好的東西當然要學習,畢竟技多不壓身。

在.NET 領域中IOC框架主流有兩個,即Autofac與Unity,這兩個都是優秀的開源框架,經過一番考量後我最終選擇了更加主流的(星星更多)Autofac。

關於Autofac的詳細使用教程請看官方文檔https://autofac.org/,我這裡主要介紹下集成到本框架的思路以及用法。
傳統使用方法通過手動註冊具體的類實現某介面,這種做法顯然不符合實際生產需求,需要一種自動註冊的方式。本框架通過定義兩個介面類:IDependency與ICircleDependency來作為依賴註入標記,所有需要使用IOC的類只需要繼承其中一個介面就好了,其中IDependency是普通註入標記,支持屬性註入但不支持迴圈依賴,ICircleDependency是迴圈依賴註入標記,支持迴圈依賴,實際使用中按需選擇即可。下麵代碼就是自動註冊的實現:

var builder = new ContainerBuilder();

var baseType = typeof(IDependency);
var baseTypeCircle = typeof(ICircleDependency);

//Coldairarrow相關程式集
var assemblys = BuildManager.GetReferencedAssemblies().Cast<Assembly>()
    .Where(x => x.FullName.Contains("Coldairarrow")).ToList();

//自動註入IDependency介面,支持AOP
builder.RegisterAssemblyTypes(assemblys.ToArray())
    .Where(x => baseType.IsAssignableFrom(x) && x != baseType)
    .AsImplementedInterfaces()
    .PropertiesAutowired()
    .InstancePerLifetimeScope()
    .EnableInterfaceInterceptors()
    .InterceptedBy(typeof(Interceptor));

//自動註入ICircleDependency介面,迴圈依賴註入,不支持AOP
builder.RegisterAssemblyTypes(assemblys.ToArray())
    .Where(x => baseTypeCircle.IsAssignableFrom(x) && x != baseTypeCircle)
    .AsImplementedInterfaces()
    .PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies)
    .InstancePerLifetimeScope();

//註冊Controller
builder.RegisterControllers(assemblys.ToArray())
    .PropertiesAutowired();

//註冊Filter
builder.RegisterFilterProvider();

//註冊View
builder.RegisterSource(new ViewRegistrationSource());

//AOP
builder.RegisterType<Interceptor>();

var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

AutofacHelper.Container = container;

代碼中有相關註釋,使用方法推薦使用構造函數註入:

框架已在Business層與Web層全面使用DI,Util層、DataRepository層與Entity層不涉及業務邏輯,因此不使用DI。

讀寫分離分庫分表

前面的IOC或許沒啥可驚喜的,但是資料庫讀寫分離分庫分表應該不會讓大家失望。接下來將闡述下框架支持Sharding的設計思路以及具體使用方法。

理論基礎

資料庫讀寫分離分庫分表(以下簡稱Sharding),這並不是什麼新概念,網上也有許多的相關資料。其根本就是為瞭解決一個問題,即資料庫大數據量如何處理的問題。

當業務規模較小時,使用一個資料庫即可滿足,但是當業務規模不斷擴大(數據量增大、用戶數增多),資料庫最終將會成為瓶頸(響應慢)。資料庫瓶頸主要有三種情況:數據量不大但是讀寫頻繁數據量大但是讀寫不頻繁以及數據量大並且讀寫頻繁

首先,為瞭解決數據量不大但是讀寫頻繁導致的瓶頸,需要使用讀寫分離,所謂讀寫分離就是將單一的資料庫分為多個資料庫,一些資料庫作為寫庫(主庫),一些資料庫作為讀庫(從庫),並且開啟主從複製(實時將寫入的數據同步到從庫中),這樣將數據的讀寫分離後,將原來單一資料庫用戶的讀寫操作分散到多個資料庫中,極大的降低了資料庫壓力,並且打多數情況下讀操作要遠多於寫操作,因此實際運用中大多使用一主多從的模式。

其次,為瞭解決數據量大但是讀寫不頻繁導致的瓶頸,需要使用分庫分表。其實思想也是一樣的,即分而治之,一切複雜系統都是通過合理的拆分從而有效的解決問題。分庫分表就是將原來的單一資料庫拆分為多個資料庫,將原來的一張表拆分為多張表,這樣表的數據量就將下來了,從而解決問題。但是,拆表並不是胡亂拆的,隨便拆到時候數據都找不到,那還怎麼玩,因此拆表需要按照一定的規則來進行。最簡單的拆表規則,就是根據Id欄位Hash後求餘,這種方式使用簡單但是擴容很麻煩(絕大多數都需要遷移,工作量巨大,十分麻煩),因此大多用於基本無需擴容的業務場景。後來經過一番研究後,發現可以使用雪花Id(分散式自增Id)來解決問題,雪花Id中自帶了時間軸,因此在擴容時可以根據時間段來判斷具體的分片規則,從而擴容時無需數據遷移,但是存在一定程度上的數據熱點問題。最後,找到了葵花寶典-一致性哈希,關於一致性哈希的理論我這裡就不獻醜了,相關資料網上一大把。一致性哈希從一定程度上解決了普通哈希的擴容問題與數據熱點問題,框架也支持使用一致性哈希分片規則。

最後,就是大BOSS,大數據量與大訪問量,很簡單隻需要結合讀寫分離與分庫分表即可,下表是具體業務場景與採用方案的關係
| 數據量\訪問量 | | |
|-|-|-|
|| 無| 讀寫分離 |
| | 分庫分表 |讀寫分離分庫分表|

設計目標

首先定一個小目標(先賺他一個億):支持多種資料庫,使用簡單,業務升級改動小。
有了目標就需要調查業界情況,實現Sharding,市面上主要分為兩種,即使用中間件與客戶端實現。

現狀調研

中間件的優點是對客戶端透明,即對於客戶端來講中間件就是資料庫,因此對於業務改動影響幾乎沒有,但是對中間件的要求就很高,目前市面上比較主流成熟的就是mycat,其對MySQL支持比較好,但是對於其他資料庫支持就比較無力(個人測試,沒有深入研究,若有不妥請不要糾結),並且不支持EF,此方案行不通。其它類型資料庫也有對應的中間件,但是都並不如意,自己開發更不現實,因此使用中間件方案行不通。

既然中間件行不通,那就只能選擇客戶端方案了。目前在JAVA中有大名鼎鼎的Sharding-JDBC,瞭解了下貌似很牛逼,可惜.NET中並沒有Sharding-NET,但是有FreeSql,粗略瞭解了下是一個比較強大ORM框架,但我的框架原來底層是使用EF的,並且EF是.NET中主流的ORM框架,整體遷移到FreeSql不現實,因此最終沒找到成熟的解決方案。

設計思路

最後終於到了最壞的情況,既沒有完美的中間件方案,又沒有現成的客戶端方案,怎麼辦呢?放棄是不可能的,這輩子都不可能放棄的,終於,內心受到了黨的啟發,決定另起爐竈(既然沒有現成的那就自己早造)、打掃乾凈屋子再請客(重構數據倉儲層,實現Sharding)、一邊倒(堅定目標不改變,不妥協),由於EF支持多種資料庫,已經對底層SQL進行了抽象封裝,因此決定基於EF打造一套讀寫分離分庫分表方案。

資料庫讀寫分離實現:讀寫分離比較簡單,在倉儲介面中已經明確定義了CRUD操作介面,其中增、刪、改就是指寫操作,寫的時候按照具體的讀寫規則找到具體的寫庫進行寫操作即可,讀操作(查數據)按照具體的讀規則找到具體的讀庫進行讀即可。

資料庫分庫分表:分庫還好說,使用不同的資料庫即可,分表就比較麻煩了。首先實現分表的寫操作,可以根據分片規則能夠找到具體的物理表然後進行操作即可,實現比較容易。然後實現分表的讀操作,這個就比較麻煩了,就好比前面的都是鬥皇以下的在小打小鬧,而這個卻是鬥帝(騎馬),但是,作為一名合格的攻城獅是不怕鬥帝的,遇到了困難不要慌,需要冷靜思考處理。前面提到過,解決複雜問題就是一個字“”,首先聯表查詢就直接不考慮支持了(大數據量進行笛卡爾積就是一種愚蠢的做法,怎麼優化都沒用,物理資料庫隔絕聯表不現實,實現難度太大放棄)。接下來考慮最常用的方法:分頁查詢、數據篩選、最大值、最小值、平均值、數據量統計,EF中查詢都是通過IQueryable介面實現的,IQueryable中主要包括了數據源(特定表)與關聯的表達式樹Expression,通過考慮將數據源與關聯的表達式樹移植到分表的IQueryable即可實現與抽象表相同的查詢語句,最後將併發多線程查詢分表的數據通過合併演算法即可得到最終的實際數據。想法很美好,現實很殘酷,下麵為大家簡單闡述下實現過程,可以說是過五關斬六將

實現之過五關斬六將

動態對象

首先考慮分表的寫操作,傳統用法都有具體的實體類型進行操作,但是分表時,例如Base_UnitTest_0、Base_UnitTest_1、Base_UnitTest_2,這些表全部保存為實體類不現實,因此需要一種非泛型方法,後來在EF的關鍵類DbContext中找到DbEntityEntry Entry(object entity)方法,通過DbEntityEntry可以實現數據的增刪改操作,又註意到傳入參數是object,由此猜測EF支持非泛型操作,即只需要傳入特定類型的object對象也行。例如抽象表是Base_UnitTest,實際需要映射到表Base_UnitTest_0,那麼怎樣將Base_UnitTest類型的對象轉換成Base_UnitTest_0類型的對象?經過查閱資料,可以通過System.Reflection.Emit命名空間下的TypeBuilder在運行時創建動態類型,即可以在運行時創建Base_UnitTest_0類型,該類型擁有與Base_UnitTest完全一樣的屬性(因為表結構完全一樣),創建了需要的類型,接下來只需要通過Json.NET將Base_UnitTest對象轉為Base_UnitTest_0即可。實現到這裡,原以為會順利成功,但是並沒有那麼簡單,EF直接報錯“上下文不包含模型Base_UnitTest_0”,這明顯就是模型的問題了,接下來進入下一關:EF動態模型緩存

動態模型緩存

通常都是通過繼承DbContext重寫OnModelCreating方法來註冊實體模型,這裡有個坑就是OnModelCreating只會執行一次,並最終生成DbCompiledModel然後將其緩存,後續創建的DbContext就會直接使用緩存的DbCompiledModel,由於最初註冊實體模型的時候只有抽象類型Base_UnitTest,所有後續在使用Base_UnitTest_0對象的時候會報錯。為瞭解決這個問題,需要自己管理DbCompiledModel緩存,實現過程比較麻煩,這裡就不詳細分析了,有興趣的直接看源碼即可。將緩存問題解決後,終於成功的實現了Base_UnitTest_0的增刪改,這時,心裡一喜(有戲)。實現了寫操作(增、刪、改)之後,接下來就是實現查詢了,那麼如何實現查詢呢?EF中查詢操作都是通過IQueryable介面實現的,IQueryable中包括了具體數據表的數據源和關聯的查詢表達式樹,那麼如何將IQueryable < Base_UnitTest >轉換為IQueryable < Base_UnitTest_0 > 並且保留原始查詢語句就成了關鍵問題。

數據源移植

根據經驗,想一舉同時移植數據源與表達式樹應該不現實,實際情況也是如此,移植數據源,通過使用ExpressionVisitor可以找到根數據源,其實是一個ObjectQuery類型,並且在表達式樹中是以ConstantExpression存在,同樣通過ExpressionVisitor則可將原ObjectQuery替換為新的,實現過程省略10000字。

查詢表達式樹深度移植

數據源移植後,別以為就大功告成了,接下來進入一個深坑(最難點),表達式樹移植,經過一番踩坑後發現,表達式樹中的所有節點都是樹狀結構,任何一個查詢(Where、OrderBy、Skip、Take等)在表達式樹中都是以一個節點存在,並且一級扣一級,也就是說你改了數據源沒用,因為數據源只是表達式樹的根節點,下麵的所有子節點還都是原來的根節點發的牙,並不能使用,那怎樣才能用新數據源構建與原數據源一樣的表達式樹呢?經過如下分析:IQuryable中的所有操作都是MethodCallExpression一層一層包裹,那麼我從外到內剝開方法,然後再從內到外包裹新的數據源,那不就模擬得一模一樣了嗎?(貌似有戲),想到先進後出腦子裡直接就蹦出了數據結構中的,強大的.NET當然支持棧了,經過一番操作(奮鬥幾個晚上),此處省略10000字,最終完成IQueryable的移植,即從IQueryable < Base_UnitTest >轉換為IQueryable < Base_UnitTest_0 > 並且保留原始查詢語句。有了分表的IQueryable就能夠獲取分表的數據了,最後需要將獲取的分表數據進行合併。

數據合併演算法

分表後的數據合併演算法主要參考了網上的一些資料,雖然分庫分表的實現方式各不相同,但是思想都是差不多的,例如需要獲取Count,只需要將各個分表的Count求和即可,最大值只需要所有分表的最大值的最大值即可,最小值只需要所有分表最小值的最小值即可,平均值需要所有分表的和然後除以所有分表的數據條數即可。最後比較麻煩的就是分頁查詢,分頁查詢需要分表排序後獲取前N頁的所有數據(不能直接獲取某一頁的數據,因為不一定就是那一頁),最後將所有表的數據再進行分頁即可。實現到這裡,已經實現了增、刪、改、查了,看似革命已經成功,其實還有最後的大BOSS:事務支持

事務支持

因為分表很可能不在同一個資料庫中,因為普通的單庫事務顯然不能滿足需求,原本框架中已經有分散式事務支持(多庫事務),這裡需要集成到Sharding中,實現過程省略10000字,最終黃天不負有心人終於實現了。

到這裡,肯定有暴躁老哥坐不住了:你前面BBB那麼多,說得那麼牛逼,到底怎麼用啊???,若文章到此為止,估計就是下圖:

鄙人則回覆如下:

深夜12點了,放鬆一下,最後介紹如何使用

實際使用

本框架支持資料庫讀寫分離分庫分表(即Sharding),並且支持主流關係型資料庫(SQLServer、Oracle、MySQL、PostgreSQL),理論上只要EF支持那麼本框架支持。
由於技術原因以及結合實際情況,目前本框架僅支持單表的Sharding,即支持單表的CRUD、分頁、統計(數量、最大值、最小值、平均值),支持跨庫(表分散在不同的資料庫中,不同類型資料庫也支持)。具體如何使用如下:

  • Sharding配置
    首先、要進行分庫分表操作,那麼必要的配置必不可少。配置代碼如下:
ShardingConfigBootstrapper.Bootstrap()
    //添加數據源
    .AddDataSource("BaseDb", DatabaseType.SqlServer, dbBuilder =>
    {
        //添加物理資料庫
        dbBuilder.AddPhsicDb("BaseDb", ReadWriteType.ReadAndWrite);
    })
    //添加抽象資料庫
    .AddAbsDb("BaseDb", absTableBuilder =>
    {
        //添加抽象數據表
        absTableBuilder.AddAbsTable("Base_UnitTest", tableBuilder =>
        {
            //添加物理數據表
            tableBuilder.AddPhsicTable("Base_UnitTest_0", "BaseDb");
            tableBuilder.AddPhsicTable("Base_UnitTest_1", "BaseDb");
            tableBuilder.AddPhsicTable("Base_UnitTest_2", "BaseDb");
        }, new ModShardingRule("Base_UnitTest", "Id", 3));
    });

上述代碼中完成了Sharding的配置:
ShardingConfigBootstrapper.Bootstrap()在一個項目中只能執行一次,所以建議放到Application_Start中(ASP.NET Core中的Startup)
AddDataSource是指添加數據源,數據源可以看做抽象資料庫,一個數據源包含了一組同類型的物理資料庫,即實際的資料庫。一個數據源至少包含一個物理資料庫,多個物理資料庫需要開啟主從複製或主主複製,通過ReadWriteType(寫、讀、寫和讀)參數來指定資料庫的操作類型,通常將寫庫作為主庫,讀庫作為從庫。同一個數據源中的物理資料庫類型相同,表結構也相同。
配置好數據源後就可以通過AddAbsDb來添加抽象資料庫,抽象資料庫中需要添加抽象數據表。如上抽象表Base_UnitTest對應的物理表就是Base_UnitTest_0、Base_UnitTest_1與Base_UnitTest_2,並且這三張表都屬於數據源BaseDb。分表配置當然需要分表規則(即通過一種規則找到具體數據在哪張表中)。
上述代碼中使用了最簡單的取模分片規則
源碼如下:

可以看到其使用方式及優缺點。
另外還有一致性HASH分片規則

雪花Id的mod分片規則

上述的分片規則各有優劣,都實現IShardingRule介面,實際上只需要實現FindTable方法即可實現自定義分片規則。
實際使用中個人推薦使用雪花Id的mod分片規,這也是為什麼前面資料庫設計規範中預設使用雪花Id作為資料庫主鍵的原因(PS,之前版本使用GUID作為主鍵被各種嫌棄,這次看你們怎麼說)

  • 使用方式
    配置完成,下麵開始使用,使用方式非常簡單,與平常使用基本一致
    首先獲取分片倉儲介面IShardingRepository
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();
//事務,使用方式與普通事務一致
using (var transaction = _db.BeginTransaction())
{
    _db.Insert(_newData);
    var newData2 = _newData.DeepClone();
    _db.Insert(newData2);
    bool succcess = _db.EndTransaction().Success;
}

上述操作中錶面上是操作Base_UnitTest表,實際上卻在按照一定規則使用Base_UnitTest_0~2三張表,使分片對業務操作透明,極大提高開發效率,基本達成了最初定製的小目標。
具體使用方式請參考單元測試源碼:
"\src\Coldairarrow.UnitTests\DataRepository\ShardingTest.cs"

最後放上簡單的測試圖:300W的表分成三張100W的表後效果


看來功夫沒白費,效果明顯(還不快點贊

展望未來

結束也是是新的開始,版本後續計劃採用前後端完全分離方案,前端使用vue-element-admin,後端以.NET Core為主,傳統的.NET將逐步停止更新,敬請期待!
文章雖然結束了,但是技術永無止境,希望我的文檔能夠幫助到大家。
深夜碼字,實屬不易,文章中難免會出現一些紕漏,一些觀點也不一定完全正確,還望各位大哥不吝賜教。
最後覺得文檔不錯,請點贊,Github請星星,若有各種疑問歡迎進群交流:
QQ群1:373144077(已滿)
QQ群2:579202910

See You


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • JFxUtils "項目地址" 介紹 這是一個JFX的工具庫,Intent可以簡單地實現打開一個新視窗並傳遞數據,DialogBuilder可以簡單地生成對話框,MyUtils有些常用的功能 使用 與`JavaFxTemplate JavaFxTemplate`模板 JavaFxTemplate模版 ...
  • 6.23 自我總結 面向對象的高階 1.isinstance/type/issubclass 1.type 顯示對象的類,但是不會顯示他的父類 2.isinstance 會顯示的對象的類,也會去找對象的父類,填寫參數是對象,類isinstance(對象,類)如果對象屬於後面的類會報Ture,反之Fa ...
  • 摘要: 主頁面的搭建(導航條下麵的區域) 個人站點 側邊欄分類展示 側邊欄標簽展示 側邊欄日期歸檔 文章詳情頁 文章內容 文章點贊點踩 文章評論 側邊欄分類展示 側邊欄標簽展示 側邊欄日期歸檔 文章內容 文章點贊點踩 文章評論 一、主頁面home.html的搭建(進一步完善) home.html頁面 ...
  • 單線程執行 python的內置模塊提供了兩個內置模塊:thread和threading,thread是源生模塊,threading是擴展模塊,在thread的基礎上進行了封裝及改進。所以只需要使用threading這個模塊就能完成併發的測試 實例 創建並啟動一個單線程 執行結果 其實單線程的執行結果 ...
  • 對象操作流 可以用於讀寫任意類型的對象 ObjectOutputStream :對象輸出字元流 WriteObject ObjectInputStream :對象輸入字元流 ReadObject 註意: 使用對象輸出流寫出對象,只能使用對象輸入流來讀取對象 只能將支持java.io.Serializ ...
  • 1. 如何讓列表的內容更容易查找 假設有這麼一個列表(數據源在本地),由於內容太多,要查找到其中某個想要的數據會比較困難。要優化這個列表,無非就是排序、篩選和高亮。 改造過的結果如上。 2. 排序 在WPF中要實現數據排序的功能有很多種,例如用Linq,但這種場景的標準做法是使用 "Collecti ...
  • 寫在前面 設計良好的系統,除了架構層面的優良設計外,剩下的大部分就在於如何設計良好的代碼,.NET提供了很多的類型,這些類型非常靈活,也非常好用,比如List,Dictionary、HashSet、StringBuilder、string等等。在大多數情況下,大家都是看著業務需要直接去用,似乎並沒有 ...
  • 最近利用周末時間,終於完成了線上轉換服務的各個功能模塊。 網站地址:http://101.201.64.215:8088 主要功能: 1.Word,Excel,PPT文件轉PDF文件。 2.PDF文件轉Word文件。 3.Word,Excel,PPT,PDF文件轉圖片文件。 4.音頻轉換,音頻分割, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...