[Develop]Lab17-Compensate

  • 8316
  • 0

[Develop]Lab17-Compensate

Lab17、Compensate

實務中,我們幾乎都避不開要撰寫與資料庫互動的程式,無論是留言板、會員資料、或是公司各種應用程式的開發…等。幾乎都無法與資料庫不扯上關係。

過去在ASP時代,交易就是我們很頭痛的一個問題。當我們開發了一個加入會員的資料輸入介面,並且把他公佈在網路上讓顧客可以藉由網路來我們設計的介面輸入

個資加入會員。這種功能到目前還是非常的常見,但是當一個使用者輸入了一大堆資料後,按下 Submit 的按鈕將資料送出之後。你撰寫好的應用程式要將這些資料寫

入資料庫當中。這時你很可能會遇到網路斷線或是資料庫忙碌…..等,許許多多突發的狀態而導致你寫入資料庫失敗。早期在ASP我們要處理這樣的交易與補償動作,可

說是非常的辛苦。然而我們也總不能寫入失敗就丟掉這些資料吧 ? 如果就這樣丟掉的話,那你的這個會員就有可能懶得再輸入一次資料來加入你設計的網站了。

在ASP.Net 出現後,我們可以運用 SQLTransaction 類別來建立交易的確認動作。但是交易失敗後的補償動作,我們還是要花一些心思來設計。例如當交易失敗,運用類

似遞迴的方式呼叫自己重新執行一次函式。但是我們希望是不是有更簡單易讀的程式撰寫方式來解決補償的問題。到了 WWF的時代我們有更彈性更輕鬆的方法來做到

補償的程式設計。這個範例我們就要來設計一個寫入資料庫失敗的簡單補償動作。


新增一個SQL資料庫與資料表。

這個範例是要模擬當程式要去寫入資料表時發生的失敗的一個補償動作,所以我們要對SQL建立一個資料表來做這個範例的測試。這個資料庫與資料表還有資料欄位的名稱

不一定要按照浩呆的設定,您可以設計製作符合您自己需求的資料庫。在這邊浩呆還是提供我建立的資料表給大家參考。針對這個範例我建立了一個資料表,我叫他

[ TempDB ]。這個資料表裡面只有兩個欄位,分別是 [ Test001 ] 與 [ Test002 ]。

clip_image001


新增一個新的WWF專案。

這個範例中我們要使用的是 [ 循序工作流程主控台應用程式 ] 。檔案名稱我們命名為 [ Lab17_Compensate ] 。

clip_image002


建立主要流程元件。

在循序工作流程中,我們建立以下的物件。包括了一個 [ CompensatableSequence ] Activity,在 [ CompensatableSequence
] Activity 中加入一個 [ codeActivity1 ]。

在下方再拉出一個 [ ifElseActivity1 ],在 [ ifElseActivity1 ] 代表條件成立左方區域加入 [ codeActivity2
] ;並且在右方加入了 [ throwActivity1] 一個執出例外的活動元件。

clip_image003

接著我們按下滑鼠右選擇程式碼檢視來進入循序工作流程的程式撰寫區塊。

clip_image004

首先我們在開頭宣告 using System.Data.OleDb;

clip_image005

接著我們在循序工作流程程式碼編輯區域裡面先來撰寫一個類別 [ ISQLDAO ]。這個類別裡面我們撰寫一個方法[ Method1 ]用來寫入資料到資料庫中並且會回傳一個布林值來

讓我們判斷是否寫入資料庫成功我們將寫入資料庫的程式碼寫在一個 Try ..Catch 中。當寫入資料庫的動作發生任何意外時,就會在 Catch
區域中回傳一個 false 的訊息。當寫入

成功時會傳入一個 True。

※ 寫入資料庫的連線字串請以你自己的資料庫為主,下列的連線字串是連到浩呆自己裝的SQL Server 上。照抄程式是不會動的喔^^|||。

clip_image006

我們接著要為這個類別作一些基本的宣告。

首先我們宣告一個 int 變數 i ,用來計算一共運行了幾次補償。宣告一個布林變數 Result用來接收寫入資料庫類別的布林值。然後為了方便我們直接在這邊就先建立了

ISQLDAO類別的物件實體,命名為 [ ISQLDAOObj ]。

clip_image007

點選在詢序工作流程中的 [ codeActivity1 ] 兩下進入程式編輯區,撰寫右下圖的程式。讓這個 Activity 負責運用ISQLDAO類別的物件實體中的
Method1方法來執行寫入資料庫的動作。

並且運用Result 變數來接收回傳值。

clip_image008

clip_image009

到循序工作流程下方的 IF 條件判斷區域,在 [ IFActivity ]的條件判斷區域我們設定一個 [ 宣告是規格條件 ],命名為 [
條件1 ]。並且將其內容式輸入 [ this.Result ]。

如果條件成立,會執行 [ codeActivity2 ] 。而條件不成立,也就是當發生例外導致寫入資料庫失敗時,會執行右邊的 [ throwActivity1
] 執出一個例外。

clip_image010

clip_image011

接著點選右邊的 [ codeActivity2 ],我們撰寫右下圖的程式來通知使用者寫入資料庫成功。

clip_image012

clip_image013

點選 [ throwActivity1 ] ,在屬性區塊裡點選 [ Fault ]來設定 Fault 的繫結屬性。

clip_image014

clip_image015

在展開的視窗中選擇繫結到新成員,在下方我們選擇 [ 建立欄位 ]後按下確定。

clip_image016

接著我們到循序工作流程的程式編輯區中,在剛剛建立出來的例外狀況中我們在裡面輸入 ( "寫入資料庫時發生失敗,執出例外…"
)。來幫助我們辨別是由哪個 Activiry執出例外的。

clip_image017


建立補償流程元件。

接著我們要來建立一個補償流程了。當資料庫寫入失敗後,我們希望的動作是程式持續的去寫入資料庫直到寫入成功。我們在[CompensatableSequenceActivity1]元件上按下滑鼠右鍵,

選擇 [ 檢視補償處理常式]。會來到補償處理常式的編輯區域。

clip_image018

在補償區域中我們建立幾個Activity1元件,如下圖。首先我們建立一個 [ WhileActivity ]元件,目的是讓程式一直嘗試寫入資料庫直到寫入成功為止。然後我們在
[ WhileActivity ] 裡面拉進了一個

[ delayActivity ] 用來設定延遲時間;讓寫入資料庫的動作每隔一秒再做一次嘗試,不要讓他太密集的寫資料庫。當然時間差可以由你自己決定啦!!,然後在
[ WhileActivity ] 放入一個 [ codeActivity ]

。在 [ WhileActivity ] 外也放入一個 [ codeActivity ]。

clip_image019

在 [ whileActivity1 ] 的屬性中,我們設定宣告式條件為 [ !this.Result ]。就是當寫入資料庫失敗時就持續的運作這個部份的程式。

clip_image020

clip_image021

點選補償範圍中的 [ codeActivity3 ],這邊我們撰寫三行程式碼。第一行是顯示這是第幾次進行這個區塊的程式動作,也就是總共運行過幾次補償。第二行是呼叫ISQLDAO類別的物件實體來

嘗試寫入資料庫。第三行是執行 i 變數的累加,這個變數是用來計算總共運行過幾次補償。

clip_image022

clip_image023

在 [ delayActivity ]元件的屬性中,我們設定 [ TimeoutDuration ] 屬性為 [ 00:00:01]。也就是讓程式延遲一秒在嘗試重新寫入資料庫。

clip_image024

clip_image025

點兩下在[ whileActivity1 ]外的[ codeActivity4],我們寫入 [ Console.WriteLine("補償寫入資料庫成功....")
] ; 來通知使用者已經將資料寫入資料庫中了。到這邊程式就撰寫完畢了,可以進入

測試的階段了。

clip_image026

clip_image027


測試結果。

我們執行這個專案,運氣好的話。可以看到如下圖一樣的程式寫入資料庫成功。

clip_image028

接著我們要來製造一個資料庫斷線的模擬情況。首先我們來到電腦管理的介面,選到左邊服務的選項。在服務中我們將 [ SQL Server(MSQLServer)
]服務停用,此時就會照成資料庫斷線。

所以當應用程式要來寫入資料庫的時候就會發生找不到資料庫的狀況。

clip_image029

在執行的畫面中,我們就可以看見程式一直在嘗試寫入資料庫中。因為這時候資料庫是斷線的,所以程式會持續嘗試。當我們在去服務裡面將SQL Server服務啟動起來後,這時程式就可以順利寫入

資料到資料庫中了。這邊我們也可以看到擲出例外的是由我們設定的[ throwActivity1 ]。

clip_image030

clip_image031