--- title: TransactionScope 咱們一起同進退,共患難 tags: ASP.NET,C#,SQL,TransactionScope --- TransactionScope 咱們一起同進退,共患難 === ###### tags: `ASP.NET` `C#` `SQL` `TransactionScope` ### :book: 關於儲存的那檔事 > **儲存**:這份檔案需要先儲存,所以<font color='red'>**儲存步驟就放我這**</font>不要複製再貼上,call我就會處理 > **陳核**:我要儲存!但是<font color='blue'>**儲存前要先存些東西**</font>,真的不行複製過來我這嗎? > **退回**:我也要!我也要!<font color='green'>**我也要儲存但是需要前處理資料**</font>,而且跟陳核處理的部分不一樣耶! > **結案**:不用擔心我!我<font color='orange'>**只要儲存就好**</font>,其他一律不處理跟負責。 > **刪除**:恩.... 我應該不用儲存吧?<font color='purple'>**反正儲存完也要刪掉**</font>,沒有要保留了不是嗎? 上面的故事,大家有沒有發現了**什麼問題點**? 沒錯!顯而易見的東西叫做「儲存資料」,而且儲存的邏輯被規定放在某個function裡 即使有其他邏輯、需求需要在儲存前或儲存中作相對應處理,卻不能把儲存邏輯放在其他地方。 :::info :bulb: 要先說明為何不能將儲存方式多放在其他地方的原因 :arrow_down: - 1. 原始資料 ``` C# var savedList = new List<string>() {"I got a book", "have to save"}; ``` - 2. 儲存資料 原始function ``` C# public async Task<bool> onlySaved(List<string> list){ var result = false; using (var scope = new TransactionScope()){ foreach (var saveObj in list) { if(string.IsNullOrEmpty(saveObj)) await savingObject(saveObj); } scope.Complete(); result = true; } return result; } ``` - 3. 儲存前 前處理 ``` C# public async Task<bool> savedAndAdding(List<string> list){ var result = false; using (var scope = new TransactionScope()){ for (var i = 0; i < list.Count(); ++i) { var saveObj = string.Format("{0}. {1}", i, ist[i]); if(string.IsNullOrEmpty(saveObj)) await savingObject(saveObj); } scope.Complete(); result = true; } return result; } ``` 兩種差別儲存方式只有在**儲存前整理、預先處理**一些雜項,但實際上可能有更多資料需要。 而且不只處理,還需要顯示,導致更多因素讓儲存function到處被複製 這樣的缺點,會讓後續<font color="red">**接手人員不好改**</font>,而且一改動就要**從頭審查程式碼**! ::: 接下來將以 C# 的 Transaction方式 進行介紹 :arrow_down: :Memo: TransactionScope建構後可以分別傳入以下三種參數 - **Required** : 當存在交易環境時則繼續使用,反之建立新的交易區塊,此為預設值。 - **RequiredNew** : 必定建立新的交易區塊。 - **Suppress** : 隱藏該交易區塊的內容,不影響原交易區塊。 --- 測試方法詳查 :arrow_right: [點我連結](https://medium.com/brettyu/%E5%A4%9A%E9%87%8Dtransactionscope%E8%88%87transactionscopeoption-bc5cccfb6091) <font size=5><center>示意圖</center></font> ```graphviz digraph graphname{ a; subgraph cluster_c{ label="A 交易區塊"; color ="olivedrab1"; style="filled"; size=500; a[label="B 交易區塊" color="orange1" shape="rect" style="filled" size=500]; } } ``` 經過上述的測試方式,結論有以下幾點 #### **Ⅰ. TransactionScope.Required** - Required 會偵測區塊外是否存在交易動作,若有則繼續使用,無則開立新的交易區塊。 - 當TransactionScope區塊內包含Required時,外部的Scope若不Commit,<font color="red">**即使內部 Commit 也不會進行更動**</font>。 :::info :arrow_right: 當外部不Commit時,內部即使Commit也不進行更動。 :A: >可以想像成上圖,當「B交易區塊」被呼叫時,「A交易區塊」已經產生等待中 這時「B交易區塊」會去使用「A交易區塊」,不會去產生新的一份交易區塊 可以視為「B交易區塊」的資料合併到「A交易區塊」內作動 所以整個「**A、B交易區塊**」皆可看成「<font color="red">**A交易區塊**</font>」 因此只要「**A交易區塊**」**不Commit**,整大段的資料就**不會變更** ::: #### **Ⅱ. TransactionScope.RequiredNew** - 不管 RequiredNew 是否含有已存在的交易區塊,皆會開啟新的交易區塊做使用。 #### **Ⅲ. TransactionScope.Suppress** - 當有多種資料庫需要Transaction時,因**各自權限不同**,所以針對不可變更的資料庫進行TransactionScope設定則使用Suppress,<font color="red">**不必建立交易區塊,也不用Commit就會即時更新**</font>。 --- #### 結論 根據以上測試的結論來看,可以整理成下列表來看 |TransactionScope選擇|Commit|(外部Trasaction)Commit|內部資料更新結果| |--|--|--|--| |Required|Yes|<font color="red">**Yes**</font>|<font color="red">**成功**</font>| |Required|No|<font color="red">**Yes**</font>|<font color="red">**成功**</font>| |Required|Yes|No|失敗| |Required|No|No|失敗| |RequiredNew|<font color="red">**Yes**</font>|Yes|<font color="red">**成功**</font>| |RequiredNew|No|Yes|失敗| |RequiredNew|<font color="red">**Yes**</font>|No|<font color="red">**成功**</font>| |RequiredNew|No|No|失敗| |Suppress|<font color="red">**Yes**</font>|Yes|<font color="red">**成功**</font>| |Suppress|<font color="red">**No**</font>|Yes|<font color="red">**成功**</font>| |Suppress|<font color="red">**Yes**</font>|No|<font color="red">**成功**</font>| |Suppress|<font color="red">**No**</font>|No|<font color="red">**成功**</font>| :ballot_box_with_check:Required時有外部看外部Transaction,沒外部就看內部Transaction :ballot_box_with_check:RequiredNew就只看內部Transaction :ballot_box_with_check:Suppress哪邊都不看 --- ### :computer: 連結 <div class="link-Table"> | 參考網站 | 連結 | |:--------------------------------------------------------------- |:------------------------------------------------------:| | 多重TransactionScope與TransactionScopeOption | [:link:][多重TransactionScope與TransactionScopeOption] | | TransactionScope 逾時問題 | [:link:][TransactionScope 逾時問題] | | C# Transaction 介紹 | [:link:][C# Transaction 介紹] | | 使用交易範圍實作隱含交易(required/requiredNew/Suppress介紹實作) | [:link:][使用交易範圍實作隱含交易] | | Suppress 分散式交易實作 | [:link:][Suppress 分散式交易實作] | [多重TransactionScope與TransactionScopeOption]: https://medium.com/brettyu/%E5%A4%9A%E9%87%8Dtransactionscope%E8%88%87transactionscopeoption-bc5cccfb6091 [TransactionScope 逾時問題]: https://blog.darkthread.net/blog/transactionscope-timeout/ [C# Transaction 介紹]: https://docs.microsoft.com/zh-tw/aspnet/web-forms/overview/data-access/working-with-batched-data/wrapping-database-modifications-within-a-transaction-cs [使用交易範圍實作隱含交易]: https://docs.microsoft.com/zh-tw/dotnet/framework/data/transactions/implementing-an-implicit-transaction-using-transaction-scope [Suppress 分散式交易實作]: https://dotblogs.com.tw/wasichris/2017/05/31/150157 </div> <style> div.link-Table > table th:nth-of-type(1) { width: 80vw; } div.link-Table > table th:nth-of-type(2) { width: 10vw; } </style>
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up