選單
GSS 技術部落格
在這個園地裡我們將從技術、專案管理、客戶對談面和大家分享我們多年的經驗,希望大家不管是喜歡或是有意見,都可以回饋給我們,讓我們有機會和大家對話並一起成長!
若有任何問題請來信:gss_crm@gss.com.tw
3 分鐘閱讀時間 (609 個字)

新、舊系統在一起的交易之路 ~ 取得 Spring.NET 的 Connection 及 Transaction

unsplash-coding092


我們有舊的元件(Workflow),連接DB是透過自行封裝 Ado.NET 的元件,
而到新開發的系統,則是使用 Spring.NET + NHibernate 。
當新、舊交雜在一起使用時,交易該如何控管呢?
最簡單的就是用 TransactionScope 去包起來,
但這時候 MSDTC 就跑起來了。
但是很多單位現在都不給開 MSDTC 了,
那要怎麼辦呢? 取得 DB Connection 及 Transaction 往內傳嗎?
要如何取得 Spring.NET 中的 System.Data.Common.DbTransaction 物件呢?



跟同事Harry討論後,DB Connection 及 Transaction 都由 Spring 來控制,

讓舊元件用的 Connection 也是來自於 Spring 生成的。

那要如何讓舊的元件在取 Connection 時,可以拿到 Spring 生成的 Connection 呢?

這時,我們可以使用 Thread Local Storage 來儲存 Connection 及 Transaction 。

疑~~~ 不是 Connection 就可以了嗎? 為什麼還需要 Transaction 物件呢?

因為 Connection.BeginTransaction 後會傳回一個 Transaction 物件,

而在 Command 執行時,除了需要 Connection 物件外,還需要 Transaction 物件哦!

可以參考「SqlConnection.BeginTransaction 方法 ()」及「SqlCommand.Transaction遇到Exception時,會變成null」。

因為 Connection 在 Spring.NET 中容易取,但是 DbTransaction 要如何取得呢?

在 Spring.NET 起交易後,可以取到 TransactionStatus 物件,

在它的 Transaction 屬性中,有一個非公用成員 connectionHolder ,

connectionHolder 的 Transaction 就是我們要的 DbTransaction ,如下圖,


但如果我們依上圖的Path,透過 Reflection 去找到的,跟本找不到那個 connectionHolder 。

後來跟 Harry 才發現要先將 TransactionStatus.Transaction 轉成 AdoTransactionObjectSupport 物件

而 AdoTransactionObjectSupport 有個 public 屬性就是 ConnectionHolder ,就可以取得 ConnectionHolder.Transaction 物件。

在一開始取得 DbTransaction 的方式如下(SpringHelper 請 Mapping 到您的 Spring.NET 物件),
var transStatus = SpringHelper.InitTransactionManagr(); //取得 Spring.NET 的 TransactionStatustry{
using (SpringHelper.GetScope())
{
var adoTxObj = transStatus.Transaction as AdoTransactionObjectSupport;
var connHolder = adoTxObj.ConnectionHolder;

//先檢查是否已建立 LocalDataStoreSlot ldsTx = System.Threading.Thread.GetNamedDataSlot("springTx");
//將 DbTransaction 放到 Thread Local Storage 之中 System.Threading.Thread.SetData(ldsTx, connectionHolder.Transaction);

// ... 新、舊交雜在一起使用 ...
//最後沒問題就 Commit SpringHelper.Tx.Commit(transStatus);

}
}
catch (Exception ex)
{
//有錯誤就 Rollback SpringHelper.Tx.Rollback(transStatus);
}
 
而舊系統原本 Command 在執行 SQL 之中,除了給它 Connection 外, 如果 LocalDataStoreSlot 有資料的話,就 Assign 給它
var ldsTx = System.Threading.Thread.GetNamedDataSlot("springTx");
var tx = Thread.GetData(ldsTx) as SqlTransaction;
if (tx != null)
command.Transaction = tx;
 
這種方式有點像是 asp.net 中的 middleware 的方式,在 begin request 時,就將 Connection 及 Transaction 放到 Thread Local Storage 之中,

所以同一個 Thread 中後面執行到需要 Connection 及 Transaction 時,就從 Thread Local Storage 拿出來用就可以了。
初探 ASP.NET MVC 多國語系(i18n)|#1: 觀念與基本做法
ASP.NET Core Middleware

相關文章

 

評論

尚無評論
已經注冊了? 這裡登入
Guest
2024/05/03, 週五

Captcha 圖像