事務使用中如何避免誤用分散式事務

renke發表於2021-09-09

1:本地事務DbTransaction和分散式事務TransactionScope的區別:

1.1:System.Data.Common.DbTransaction:

本地事務:這個沒什麼好說了,就是單個事務,每種資料庫都有自己的實現,事務的深度內涵可以搜尋檢視相關的文章,不是本文介紹的重點。

1.2:System.Transactions.TransactionScope:

分散式事務,需要新增引用System.Transactions,同時啟用MSDTC分散式事務服務:通常使用方式為:

圖片描述 using (System.Transactions.TransactionScope ts = new System.Transactions.TransactionScope())
 {
                //程式碼塊A
                //程式碼塊B
                ts.Complete();//提交事務
 }圖片描述

分散式事務本質上是引入了第三方裁判,來想辦法對多個本地事務監控同時成功或同時失敗,這裡分享幾個知識點:

A:如果程式碼塊裡,若存在兩個或以上資料庫連結DbConnection,則需要啟動微軟的MSDTC分散式事務服務。

用命令列啟動或停止服務:

圖片描述 

B:如果程式碼塊裡,只有一個資料庫連結DbConnection,那麼實際上只是本地事務在處理,就算MSDTC分散式事務服務沒啟動,也不會報錯。

C:對於TransactionScope包含的程式碼塊,本質是監控了程式碼塊裡資料庫連結DbConnection的個數,如果有多個不同的物件,則引入MSDTC當裁判,而實際執行的事務的還是各個本地事務。

D:MSDTC總是不夠穩定,我在測試時兩個簡單的事務一起時,按住F5不停重新整理,竟然能把MSSQL服務也給掛了,而用本地事務就算跨庫也不會有問題。

 

所以,不是必須的情況,儘量不要引入分散式事務,應該避免使用TransactionScope來包含事務塊的衝動。 


2:可以用本地事務解決,避免使用分散式事務場景:

2.1:專案只有一個資料庫,這個是最應該避免,多個表間的事務, 完全是本地事務可處理的範圍:

問題:一個程式碼塊裡N個實體類雜交操作,每個實體類帶有各種的資料庫連結,從而引發了MSDTC。

可以:共用一個DbConnection物件,來避免啟用MSDTC。

 

2.2:專案多個資料庫,如果資料庫間使用了相同的訪問賬號和密碼,這種情況也可以避免:

每種資料庫有自己的解決方式:像MSSQL,跨庫處理只要加字首(dbname..tablename)就可以,因此也使的只使用本地事務就可以處理了。

 

3:回顧下我以前的專案場景:

3.1:從下圖是我08年在中域的專案:有19個資料庫,對於資料庫連結而言,唯一的不同只有資料庫的名稱:

圖片描述 

進化:能不能只保留一條,其它的透過動態切換資料庫名稱來改連結字串?

 

3.2:那時候,我的架構還是很新手,透過CodeSmith生成了大量的程式碼檔案:

實體類專案,工廠專案,介面專案,資料操作,還有大量的增刪改查儲存過程,只是為了基礎的增刪改查而且只針對MSSQL。

圖片描述

隨便展開一個專案都會看到大量的資料夾,裡面有大量的檔案,而這些東東,都是程式碼生成器的傑作:

圖片描述 圖片描述圖片描述

19個資料庫啊,NN個表,光生成這些基本的增刪改查,整個專案就好像高階大氣上檔次了。

進化:能不能消滅這些大量的檔案,簡單是我們不斷追求的目標。

 

3.3:這麼多資料庫,如何跨資料庫事務?

對於生成的大量的實體,每個表的操作都是一個新的連結,單庫間的事務都必須MSDTC了,更別說19個庫間的跨庫事務了。

進化:能不能本地事務搞定這些,這是每個ORM可以思考的方向。

 

4:CYQ.Data 提供的解決方案: 

為了消滅上述的那些大量的生成檔案,我在後續新的公司寫了傳統的ORM框架:XQData(這個框架一直沒露過面,也只是支援MSSQL,用反射消滅了好多層,只留下實體層)。

對於框架的演進,多數都來源於專案中遇到的問題,或複雜的場景,需要解決或者簡化,才有了不斷升級的可能,並不是無中生有,因此,一個框架,如果不能不斷在在專案中實戰,那麼很多問題和細節等可能都無法發現,更新也會遙遙無期。 

而CYQ.Data的不斷升級,說明我一直在奮戰在一線的編碼生涯中和網友各大專案中的實戰反饋中。 

 

下面針對最近的最佳化調整,演示下CYQ.Data是怎麼解決上面提到的幾個問題:

4.1:多個資料庫的資料庫連結切換:

A:先用配置工具生成針對多資料庫的列舉檔案,和成demo和test兩個資料庫:

圖片描述

兩個資料庫就生成兩次了。

B:配置一個預設的連結字串,到Demo資料庫:

C:列印操作Test資料庫表的連結字串:

using (MAction action = new MAction(TestEnum.Users))
            {
                Console.WriteLine(action.ConnectionString);
            }

輸出:

圖片描述 

這裡自動切換了資料為名稱為新的連結,而我動手腳的地方就是在列舉的名稱了。

4.2:本地多資料庫跨事務,示例:

圖片描述            AppDebug.OpenDebugInfo = true;
            AppDebug.Start();
            using (MAction action = new MAction(DemoEnum.Users))
            {
                 action.BeginTransation();//開啟事務
                 action.Fill(12);
                Console.WriteLine(action.ConnectionString);//列印資料庫連結
                action.ResetTable(TestEnum.Users);//切換資料庫
                Console.WriteLine(action.ConnectionString);//列印資料庫連結
                action.Fill(12);
                action.EndTransation();
            }
            Console.WriteLine(AppDebug.Info);//輸出所有執行的SQL語句。
            AppDebug.Stop();圖片描述

輸出的結果:

圖片描述

 

說明:在事務中,當檢測到事務開啟時,為了使用本地事務,並沒有切換資料庫,而是採用了字首來執行操作。

 

 

如果註釋掉程式碼中的事務,則是直接切換資料庫連結,輸出會如下圖:

圖片描述 

說明:如果沒有開啟事務,則直接切換了資料庫連結,並消消滅字首語法。

總結:

對於.NET領域,微軟除了提供這個不太穩定的MSDTC,似乎沒有發現其它分散式事務的解決方案,好在一般的專案,我們在本地事務就可以處理。

希望微軟可以在一些重點分散式上多做點研究、普及和推廣,提供分散式相關專案的解決方案,別整天操碎心在那些簡單的增刪改查上。

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/430/viewspace-2806526/,如需轉載,請註明出處,否則將追究法律責任。

相關文章