以使用 TransactionScope 來說,為了確保系統中全程採用 Local Transaction,
重點在於在交易過程中必須使用單一的 connection,且不可以有開開關關的動作。
(關於 MSDTC 的說明請參考附註中 Darkthread 大大的.NET分散式交易程式開發FAQ)
但是很不幸的,舊的底層元件(Entity)為了簡化外部程式的寫法, 主動把 connection 物件給包了起來,並且在每個 public 的 CRUD Method 中去 open & close connection,因此只要在 TransactionScope 中使用多個 Entity, 或者先呼叫某個 Entity 的 Select 再呼叫 Save(造成 connection 開關多次), 就會導致該交易從 Local Transaction 被 automatic escalate 為 MSDTC, 進而造成 MA 時莫大的痛苦。
(幾乎每次 MSDTC 出錯時,根據當時的 System Configuration 都可以在網路上找到相對應的案例。也就是說,各種可能導致 MSDTC 出錯的環境組合幾乎是無窮盡的 =.=”)
為了在「避免舊系統大幅改寫」的前提下,修改底層元件的寫法以設法避免 MSDTC,
我們需要一個 Global 的地方以存放共用的 connection (以及相關的交易控制資料),
在一番討論 & survey 之後,決定採用 ThreadLocalStorage (簡稱 TLS) 這個技術。
以下是 TLS 的基本介紹:
- TLS 的技術可以回溯到 Win32 multi-threaded programming,在 .NET 的世界中也有一套相對應的作法。
- TLS 的基本原理是,在每個 thread 中分配一塊可以用來儲存資料的地方,只要在該 thread 中執行的 method 均可存取這些資料。
- TLS 的一個好用之處,在於可在不修改現有程式碼(不管是改不動還是根本就沒有 source code)的情況下,在系統中增加(效能分析)用的 tracking information(有一點 AOP 的感覺)。對我目前面臨的問題來說,剛好可以當作 Global Data Storage 來儲存 connection 物件。
- 在 TLS 中,一份資料對於某一組「thread + AppDomain」來說是 unique 的。TLS 不能像 .NET Remoting 技術那樣的 cross AppDomain boundary。
(.NET Remoting 還蠻複雜的,看來沒時間仔細研究。不過以後會被 WCF 取代)
- 儲存於 TLS 的資料一律是 Object 的資料型態,因此必須自己 handle 轉型。
但根據手上的資料來看應該是可以解決 MSDTC 的問題。
我的小小 TLS 範例程式可以在這裡下載。
PS. 關於 MSDTC 的說明,可參考 Darkthread 大大在 Run!PC 上發表的文章,如果忘記這個連結位置的話,可以 google「darkthread TransactionScope」,在第二個 result「Browse by Tags - Darkthread」中就可以找到「.NET分散式交易程式開發FAQ」。
沒有留言:
張貼留言