程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF從理論到實踐(12):事務

WCF從理論到實踐(12):事務

編輯:關於.NET

本文目的

通過閱讀本文,您能了解以下知識

1) 如何在WCF中實現事務?

2) 談談事務隔離方式的相關知識

3) 事務的實現會給我們編程帶來什麼樣的阻力?

4) 一筆帶過,WCF是如何實現分布式事務的?

5) 代碼不騙人,用一個銀行存取款的范例來演練WCF事務

本文適合的讀者

本文適合WCF初學者,學習本文之前,您最好閱讀一下WCF從理論到實踐系列文章的前幾篇

如何在WCF中實現事務?

事務原本是一件難於實現的事情,可WCF總是能化腐朽為神奇,它能夠通過簡單的聲明式編程方式,便可以實現分布式的事務,下面就來看下實現此目標的功臣:

1) TransactionFlowAttribute:操作契約(OperationContractAttribute)的一個屬性,它能夠指示所屬操作(Operation)的事務選項(TransactionFlowOption)。

2) TransactionFlowOption:它是TransactionFlowAttribute構造函數中的參數,是一個枚舉(enum),包括三個枚舉項NotAllowed:不允許事務,是缺省值;Allowed:允許事務,意味著事務可有可無;Mandatory:強制事務,表示事務是必須的。

3) TransactionAutoCompleteOnSessionClose:它是操作行為(OperationBehaviorAttribute)的一個屬性,用於標注事務完成之後,服務端實例是否自動釋放,這個屬性和服務對象實例模式緊密相關,使用的時候,應該著重小心,下面也會有說明。

4) TransactionIsolationLevel:也是操作行為(OperationBehaviorAttribute)的一個屬性,用於指示事務隔離方式(isolation level).包括5中選項:Any,ReadUncommitted,ReadCommitted,RepeatableRead,Serializable,事務的隔離方式相關知識比較復雜,留作文章的第二點中將具體闡述

5) TransactionTimeout:也是操作行為(OperationBehaviorAttribute)的一個屬性,用於指示事務的超時時間,默認為TimeSpan.Zero,表示不會受超時時間的限制..:: OperationBehaviorAttribute:也是操作行為(OperationBehaviorAttribute)的一個屬性,用於指示分布式事務選項,如果設置為true,那麼必須在事務范圍(Transaction Scorp)內。

通過上面幾個屬性的使用,我們便能夠輕松的在WCF中實現事務以及分布式事務。具體實現方式可以參考代碼范例

談談事務隔離方式的相關知識

單純的事務存在著下面三個問題

1) 髒讀:簡單的說就是事務一在某一時刻更改了數據,恰恰這個更改的數據被事務二讀取,而事務一卻最終失敗,導致數據回滾,那事務二就是一個受騙者

2) 非可重復性讀取:同一數據每次讀取的結果都不一樣就是非可重復讀取。比如事務一要讀取的數據務二改變,這就是非可重復性讀取

3) 幻讀:很簡單,比如事務一在查詢數據中,事務二卻插入了一個符合查詢條件的數據,這樣就造成新插入數據的幻讀。

三種問題的解釋可能比較難於理解,其實簡單的說,髒讀是讀了別人正在更改的數據,而可重復讀取是更改了別人正在讀的數據,而幻讀呢則是讀了別人還未來得及插入,更改或者刪除的數據,我想這樣理解就簡單多了。

針對上面不同的問題,可以設置事務的不同隔離方式來防止問題的發生,事務的隔離方式又包括

1)Any: 組件的隔離級別是從調用組件的隔離級別獲得的。如果組件是根組件,則隔離級別用於 Serializable 中。

2)ReadUncommitted:讀取未提交數據,該方式在讀取數據時保持共享鎖定以避免讀取已修改的數據,但在事務結束前可以更改這些數據,這導致非可重復讀取或幻讀。

3) ReadCommitted:讀取提交數據, 發出共享鎖定並允許非獨占方式的鎖定。該方式與讀取未提交數據相相似,這種方式看似和讀取未提交數據相似,但有一個區別,事務的只讀鎖在移到下一行的時候,會解鎖,而寫入鎖卻只有在事務完成或者被中止後才解鎖,事務要等待所有寫入鎖解鎖。

4) RepeatableRead:可重復性讀取,與讀取提交數據相似,在查詢中使用的所有數據上放置鎖,以防止其他用戶更新這些數據。防止非可重復讀取,但幻讀行仍有可能發生。該方式是只讀鎖也要等到事務結束或者中止才解除

5) Serializable:在完成事務前防止更新或插入。

從上面的描述看,幾種隔離方式比較難於區分,但它們能解決事務面臨的不同問題,也許記住這些更方便的了解隔離方式

隔離級別 ReadUncommitted ReadCommitted RepeatableRead Serializable 髒讀 Yes No No No 非可重復性讀取 Yes Yes No No 幻讀 Yes Yes Yes No

從上表可以看出隔離方式除了Any之外,一級比一級嚴厲。Any是一脈相承的,如果它沒有可繼承的,它將是最嚴厲的Serializable

事務的實現會給我們編程帶來什麼樣的阻力?

1) 指定了TransactionFlow(TransactionFlowOption.Mandatory),而Binding卻沒有設置TransactionFlow為true 此時會出現類似"Bank"協定上至少有一個操作配置為將 TransactionFlowAttribute 屬性設置為"強制",但是通道的綁定"WSDualHttpBinding"未使用 TransactionFlowBindingElement 進行配置。沒有 TransactionFlowBindingElement,無法使用設置為"強制"的 TransactionFlowAttribute 屬性。這樣的錯誤提示。

2) 設置了[OperationBehavior(TransactionScopeRequired=true)]的操作,卻沒有在TransactionScorp中執行,會發生類似"服務操作需要事務成為流"的異常,截圖如下:

3) 也許上面兩個問題都是不是問題的問題,那這一點的確是需要我們研發人員注意的,否則我們會吃虧不少。這點涉及到事務和服務實例模式的聯系,我們通過學習WCF從理論到實踐:實例模式和對象生命周期 我們都學習到了實例在PerSession或者Single模式下不會每次都創建和消亡,這的確是一個不爭的真理,可在這裡卻受到了挑戰,不信你可以編寫一個程序,即使用你最放心的Single模式,那時不是就是說服務實例是一次創建,終身受用呢?下面就看看我第一次編寫范例程序後得到的運行結果,我如下定義Bank

可在調用的時候,我卻發現了一個很奇怪的問題,按照理論來說,Bank服務實例應該只創建一次,可運行的截圖卻是如下:

這個結果是不是令大家大失所望呢?這是因為實現了事務的得服務還要受到TransactionAutoCompleteOnSessionClose的限制,該屬性默認情況是true,它指示WCF在事務操作完成之後強制銷毀服務實例,相當於調用服務的Dispose()方法進行釋放,盡管是PerSession或者Single都難逃它的法網。如果想維持實例模式,可以將其設置為false,更改後運行效果便可如期望一致效果圖不再給出。

4) 本文更多的實現了分布式任務,分布式任務要使用TransactionScrop這個類,有關它的一些注意事項可以參考我以前的這篇文章:兩種實現事務方法的比較

一筆帶過,WCF是如何實現分布式事務的?

WCF實現事務的依據是基於WS-AtomicTransaction標准,比較底層的東西,應該屬於XXX內幕系列,本文不作詳細闡述,如有興趣,可以查看園子中Kevin Li 兄弟的幾篇文章,我列在下面,希望Kevin Li不要見怪

1) 基於WS-AtomicTransaction標准的WCF遠程分布式事務(一)

2) 基於WS-AtomicTransaction標准的WCF遠程分布式事務(二)

3) 基於WS-AtomicTransaction標准的WCF遠程分布式事務(補充)

代碼不騙人,用一個銀行存取款的范例來演練WCF事務

制作了一個小范例,用於演示事務的實現,示例的情形如下

存在兩個服務:1)IATMServer:它是模擬銀行的ATM機器的服務 2)IBank,它模擬銀行的賬戶服務。建立一個客戶端用於模擬ATM機,我們的操作步驟如下:

1) 插卡

2) 存款

3) 取款

4) 拔卡

操作比較簡單,不做贅述,需要注意的是當取款的時候,如果取款金額大於余額的時候,系統會抱錯,而賬戶余額不會更改。運行效果圖

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved