文章出處

一:從事務的歷史說起

  知已知彼,百戰不敗。想了解事務,我們從事務的歷史說起。

  在Windows平臺上,事務的概念最開始出現在關系型數據庫中,但是隨著.net平臺的發展,事務包括的的范圍也越來越寬,先一睹為快,

  在關系型數據庫中的事務是通過begin transaction,rollback transaction, commit 等關鍵字來實現事務的。

BEGIN TRANSACTION  
UPDATE [dbo].[T_ACCOUNT] SET BALANCE = BALANCE + @amount WHERE ID = @toAccount  
IF @@ERROR <> 0   
BEGIN 
    ROLLBACK TRANSACTION  
END 
ELSE
    COMMIT TRANSACTION 

  隨著面象對象的發展,.net的誕生,在.net 1.* 的版本中,可以通過ADO.NET來實現數據庫的事務。把事務交給業務程序來控制,使業務程序的本職發揮的淋漓盡致,而從數據庫的角度來看,數據庫也能更專一的進行數據的存儲。達到了各盡其責的效果。

using (DbTransaction transaction = connection.BeginTransaction())
 {
    command.Transaction = transaction;
     try
    {
        command.ExecuteNonQuery();
        transaction.Commit();
    }
    catch (Exception ex)
    {
        transaction.Rollback();
        throw new Exception(ex.Message);
    }
}

  萬物是發展的,程序的發展也是永無止境的。某天有一個需求:創建一個客戶信息,其中包括姓名和頭像。姓名保存在數據庫,頭像保存在服務器的硬盤中。姓名和頭像的保存有一個失敗都是一個不完整的操作,都要回滾到初始狀態。用ADO.NET的事務顯示不能實現這個要求。因為回滾資源包括了數據庫硬盤。基于這種情況,.net 2.0推出了System.Transactions事務。

using (TransactionScope transactionScope = new TransactionScope())
{
    bankService.Pay("111", 50);
    bankService.Receipt("222", 50);
     transactionScope.Complete();
}

  System.Transactions名稱空間下的事務,是.net的主推事務。

二:事務有關概念

  第一節,我們都用代碼把事務實踐了一把,那還有必要來說事務的概念和事務在運行過程中涉及到的對象呢?如果你想深入了解事務,這一步是必須的。

     事務的定義和屬性:

  1,什么是事務:它是一個操作序列,這些操作要么都執行,要么都不執行,它是一個不可分割的工作單位。

  2,事務特性:接觸事務,都是從事務的ACID開始,原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)。每個特性的定義僵硬,枯燥,不易理解,讀了好幾篇都有讓人想跳樓的欲望。今兒換一個方式來說事務特性。

  銀行轉款是事務的經典示例,可能因為錢與銀行扯的上關系,一提到銀行,大家都精神倍爽,為了不另類,所以我也決定用銀行轉款來說事務的四大特性。

  2.1:原子性:銀行轉款分為"轉出"和"接收"兩步,比如給異地結婚的朋友送禮金,自己的錢已經轉出去了,但是朋友沒有收到禮金,這時大家都心急如焚。所以轉款必須要保證"轉出"和"接收"要么都成功,要么都不成功。這就是轉款的原子性。

  2.2:一致性:給朋友轉款888元RMB作為婚禮的禮金,但是朋友只收到777元RMB。這時你不爽了,你朋友也不爽,所以轉款要必須保證數據的一致性。

  2.3:隔離性:轉款分為"轉出"和"接收"兩步,理論上是可以同時進行的,但是在實際生活中確有時間差,即使相差0.0001秒,在這段時間里,自己的賬戶和朋友的賬戶都不能進行查詢操作,即使查詢了,也是處于一種等待狀態。在這期間外界無法對數據進行查詢訪問,所以稱之為隔離性。

  2.4:持久性:轉款這個操作被銀行記錄起來,過很多年后,你都還能查詢到轉款這個記錄。這就是持久性。

   事務涉及的對象:

  1,資源:應用程序存儲和獲取數據的地方,可以是數據庫,文件,也可以是內存。如果是應用程序的事務塊代碼中涉及到的數據庫,文件,內存,那這些資源就稱為事務型資源

  2,資源管理器:在事務模型中,應用不是直接訪問資源,而是通過中間介訪問資源,這個中間介就叫資源管理器。資源分為可持久化資源(對應了持久化資源管理),易失資源(對應了易失資源管理器)。

  3,事務管理器:實現事務的開始,提交,回滾。

  事務提升:

  要認識事務提升,必須要弄清楚事務管理器的類型。如下作了非常詳細的介紹:

  1:輕量級事務管理器:作用于開啟事務的應用程序域,只能包含一個持久化資源,如果再添加一個持久化資源,將被輕量級事務管理器忽略。但是可以登記多個易失資源。目前輕量級事務管理器只支持SQL 2005以及SQL2005以上的版本持久化資源。

  3:內核事務管理器:在Vista被引入,并后續于Windows Server 2008,WIN7。引入內核事務管理器主要是把文件管理(NTFS文件系統)和注冊表管理納入事務范疇。我們將那些支持事務的文件系統和注冊表叫作事務型文件系統(TxF)和事務型注冊表(TxR)。 之所以稱為內核事務管理器,是因它運行在內核模式上,而不是在用戶模式上。同樣內核事務管理器只支持一個持久化資源。

  3:分布式事務協調器:每一臺電腦上只有一個分布式事務協調器,它管理了當前計算機的所有事務資源。它可以跨程序域,跨進程,跨機器,跨網絡來執行事務。當事務跨機器時,每臺機器的分布式事務協調器按照相應的協議工作,實現對整個事務的管理,它對應的事務管理協議有Ole-Tx和WS-Atomic Transaction(WS-AT)這些。 分布式事務協調器能夠管理一個分布式事務涉及的所有事務型資源,不管具體的事務型資源分布在何處。

  事務提升:事務是一個動態執行的操作序列,在整個過程中,不可能預知資源的登記情況。所以輕量級事務管理器作為默認的事務管理器,隨著事務的逐步執行,如果涉及到內核事務資源,那么將提升為內核事務管理器。如果出現對多個事務資源的訪問,或者當前事務涉及跨域(調用另外一個服務),就會提升為分布式事務協調器。Windows采用事務提升機制進行事務管理器的選擇。

  

三:事務的分類

  1:本地事務

  輕量級事務管理器,內核事務管理器都只支持本地事務。本地事務相對簡單,這兒不作重點簡述。

  2:分布式事務

  理解分布式事務是怎樣實現的,事務提交樹是關鍵。

  事務提交樹:事務提交樹的根是事務初始化服務所在的機器的DTC,它在整個事務提交過程中充當著總協調者,又被稱為全局提交協調器。資源管理器充當著事務提交樹的葉子節點,它們的父結點為本機的DTC,分布于不同機器的DTC按照事務的傳播路徑形成了上下級關系。

  

  在一個分布式事務中,事務的初始化和提交是屬于一個對象,只有最初開始的事務才能被提交,我們將這種能被初始化和提交的事務稱作可提交事務。隨著參與者逐個登記到事務中,它們本地的事務實際上依賴著這個最初開始的事務,所以我們稱這種事務叫依賴事務。

四:示例

  文件事務

  在MSDN上對文件事務有詳細的闡述  使用文件系統事務增強您的應用程序  我們如果是仔細閱讀這篇文章不難發現他提供了一個.exe類型文件的下載。先把這個TxF2007_07.exe文件下載到本地硬盤,執行它,可以得到一個關于 c#的 KtmIntegration.csproj 的項目,我們用visual studio來打開這個項目,并且重新重成這個項目,可以得到一個KtmIntegration.dll文件。在你要實現的文件事務的項目中引入這個.dll文件,那你就可以很順利的實現文件事務的操作了。具體代碼:

using System;
using System.IO;
using System.Transactions;
using Microsoft.KtmIntegration;

namespace Exercise.WebLocalTransaction
{
    public partial class Test02 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            using (TransactionScope transactionScope = new TransactionScope())
            {
                try
                {
                    FileStream stream = TransactedFile.Open(
                        @"D:/Sam Xiao.txt"
                        , FileMode.OpenOrCreate
                        , FileAccess.ReadWrite
                        , FileShare.ReadWrite);
                    StreamWriter writer = new StreamWriter(stream);
                    writer.WriteLine(String.Concat("執行一個事務代碼:",DateTime.Now.ToString(),Environment.NewLine));
                    writer.Close();
                    //int x = 0;
                    //int y = 10;
                    //int z = y / x;
                    transactionScope.Complete();
                }
                catch
                {

                }
            }
        }
    }
}

不要忘記了引入using Microsoft.KtmIntegration;名稱空間。在段代碼沒有異常的情況下,我們可以看到D盤里順利創建了一個關于Sam Xiao.txt的文件。我們故意在這段代碼中拋出一個被0整除的異常,那么整個操作就會回滾。

  分布式事務

  在.net平臺上,主要是通過WCF的手段來實現程序的分布式開發。在WCF事務體系:主要解決了事務在服務中的流轉,以及解決服務內部直接或間接訪問事務型資源的協作。

  用WCF來演示事務的時候,要選擇好WCF的綁定類型,有一部份綁定是不支持WCF的事務傳播的。我們選擇wsHttpBinding 來做WCF的事務演示。

  1,首先定義好WCF的服務契約

[ServiceContract(Name = "IBankingService")]
public interface IBankingService
{
      
    [TransactionFlow(TransactionFlowOption.Mandatory)]
    [OperationContract(Name = "Transfer")]
    void Transfer(string fromAccountId, string toAccountId, double amount);

    [TransactionFlow(TransactionFlowOption.Mandatory)]
    [OperationContract(Name = "Pay")]
    bool Pay(String accountID, double amount);

    [TransactionFlow(TransactionFlowOption.Mandatory)]
    [OperationContract(Name = "Receipt")]
    bool Receipt(String accountID, double amount);
}

  2,實現WCF的服務

[ServiceBehavior(TransactionIsolationLevel = System.Transactions.IsolationLevel.Serializable)]
public class BankingService : IBankingService
{
    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public void Transfer(string fromAccountId, string toAccountId, double amount)
    {
        throw new NotImplementedException();
    }

    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public bool Pay(string accountID, double amount)
    {
        throw new NotImplementedException();
    }

    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public bool Receipt(string accountID, double amount)
    {
        throw new NotImplementedException();
    }
}

  3,WCF宿主配置

<system.serviceModel>
      <behaviors>
          <serviceBehaviors>
              <behavior name="sBehaviorConfig">
                  <serviceMetadata httpGetEnabled="true" />
                  <serviceDebug includeExceptionDetailInFaults="true" />
              </behavior>
          </serviceBehaviors>
      </behaviors>

      <bindings>
        <wsHttpBinding>
          <binding name="wshttpConfig" transactionFlow="true" >
            <security mode="None" />
          </binding>
        </wsHttpBinding>
      </bindings>
      
      <services>
        <service name="Exercise.Service.BankingService" behaviorConfiguration="sBehaviorConfig">
          <endpoint address="mex"  binding="wsHttpBinding" bindingConfiguration="wshttpConfig" contract="Exercise.Contract.IBankingService"></endpoint>
        </service>
      </services>
      <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    </system.serviceModel>

  4,WCF客戶端配置

<system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="WSHttpBinding_IBankingService" transactionFlow="true">
          <security mode="None" />
        </binding>
      </wsHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:9100/BankingService.svc/mex"
          binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IBankingService"
          contract="Exercise.Contract.IBankingService" name="WSHttpBinding_IBankingService" />
    </client>
  </system.serviceModel>

  5,調用服務

IBankingService bankService = WcfProxy.CreateProxy<IBankingService>("WSHttpBinding_IBankingService");
protected void Page_Load(object sender, EventArgs e)
{
    using (TransactionScope transactionScope = new TransactionScope())
    {
        bankService.Pay("111", 50);
        bankService.Receipt("222", 50);
        transactionScope.Complete();
    }
}

  此時我們WCF演示事務的五步曲就完成了。我們做敏捷開發都知道,可運行的代碼高于詳細的文檔。如果還有不太明白的地方,可以在網上搜索,也可以留言問我。

五:總結

  感覺"贊"的幫忙【推薦】,你們的推薦是我的動力。

  滴水之恩,當涌泉相報。回報幫助過我的人,以及需要我幫助的人源碼下載

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()