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

如下內容來源與:http://www.cyqdata.com/cyq1162/article-detail-54453數據庫

 

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當裁判,而實際執行的事務的仍是各個本地事務。ui

D:MSDTC老是不夠穩定,我在測試時兩個簡單的事務一塊兒時,按住F5不停刷新,居然能把MSSQL服務也給掛了,而用本地事務就算跨庫也不會有問題。編碼

 

因此,不是必須的狀況,儘可能不要引入分佈式事務,應該避免使用TransactionScope來包含事務塊的衝動。 spa

 

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,彷佛沒有發現其它分佈式事務的解決方案,好在通常的項目,咱們在本地事務就能夠處理。

但願微軟能夠在一些重點分佈式上多作點研究、普及和推廣,提供大型項目的解決方案,別成天操碎心在那些簡單的增刪改查上。

相關文章
相關標籤/搜索