事務使用中如何避免誤用分布式事務(System.Transactions.TransactionScope)


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數據庫:

<add name= " Conn " connectionString= " server=.;database=demo;uid=sa;pwd=123456 "/>

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,似乎沒有發現其它分布式事務的解決方案,好在一般的項目,我們在本地事務就可以處理。

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

 

新的一年,要重新賣身了,打算漂泊,城市不限,歡迎大伙推薦買主,謝謝。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM