Share via


在單一階段和多重階段中認可交易

交易所使用的每項資源都會受到資源管理員 (RM) 的管理,而這些資源管理員在採取行動時必須經過交易管理員 (TM) 的協調。將資源登記成為交易中的參與者 主題討論如何在交易中登記資源 (或多項資源)。本主題討論如何在眾多登記的資源中協調要認可的交易。

在交易結束時,應用程式會要求認可或復原交易。交易管理員必須消除某些資源管理員投票決定認可,而其他資源管理員卻投票決定復原交易之類的風險。

如果您的交易涉及一個以上的資源,則您必須執行兩階段交易認可 (2PC)。兩階段交易認可通訊協定 (準備階段與認可階段) 可確保當交易結束時,對全部資源的所有變更都能全部經過認可,或是全部復原回來。接著所有參與者都會收到最後結果的通知。如需兩階段交易認可通訊協定的詳細討論資訊,請參閱 Jim Gray 所著之《Transaction Processing : Concepts and Techniques (Morgan Kaufmann Series in Data Management Systems) ISBN:1558601902》一書說明。

您也可以藉由參與單一階段交易認可通訊協定來最佳化您的交易效能。如需詳細資訊,請參閱使用單一階段交易認可和可提升單一階段告知進行最佳化

如果您只是想要知道交易的結果,但不想參與投票,則應該註冊 TransactionCompleted 事件。

兩階段交易認可 (2PC)

在第一個交易階段,交易管理員會查詢每個資源,決定是否應該認可或復原交易。在第二個交易階段,交易管理員會將其查詢結果通知每個資源,讓資源執行任何必要的清除作業。

為了參與這種交易類型,資源管理員必須實作 IEnlistmentNotification 介面,以便在 2PC 期間提供由 TM 所呼叫的方法做為告知項目。下列範例將說明此類實作。

Public Class EnlistmentClass
    Implements IEnlistmentNotification

    Public Sub Prepare(ByVal myPreparingEnlistment As PreparingEnlistment) Implements System.Transactions.IEnlistmentNotification.Prepare
        Console.WriteLine("Prepare notification received")

        'Perform transactional work

        'If work finished correctly, reply with prepared
        myPreparingEnlistment.Prepared()
    End Sub

    Public Sub Commit(ByVal myEnlistment As Enlistment) Implements System.Transactions.IEnlistmentNotification.Commit
        Console.WriteLine("Commit notification received")

        'Do any work necessary when commit notification is received

        'Declare done on the enlistment
        myEnlistment.Done()
    End Sub

    Public Sub Rollback(ByVal myEnlistment As Enlistment) Implements System.Transactions.IEnlistmentNotification.Rollback
        Console.WriteLine("Rollback notification received")

        'Do any work necessary when rollback notification is received

        'Declare done on the enlistment
        myEnlistment.Done()
    End Sub

    Public Sub InDoubt(ByVal myEnlistment As Enlistment) Implements System.Transactions.IEnlistmentNotification.InDoubt
        Console.WriteLine("In doubt notification received")

        'Do any work necessary when indout notification is received

        'Declare done on the enlistment
        myEnlistment.Done()
    End Sub
End Class
class myEnlistmentClass : IEnlistmentNotification
{
    public void Prepare(PreparingEnlistment preparingEnlistment)
    {
        Console.WriteLine("Prepare notification received");

        //Perform transactional work

        //If work finished correctly, reply prepared
        preparingEnlistment.Prepared();

        // otherwise, do a ForceRollback
        preparingEnlistment.ForceRollback();
    }

    public void Commit(Enlistment enlistment)
    {
        Console.WriteLine("Commit notification received");

        //Do any work necessary when commit notification is received

        //Declare done on the enlistment
        enlistment.Done();
    }

    public void Rollback(Enlistment enlistment)
    {
        Console.WriteLine("Rollback notification received");

        //Do any work necessary when rollback notification is received

        //Declare done on the enlistment
        enlistment.Done();
    }

    public void InDoubt(Enlistment enlistment)
    {
        Console.WriteLine("In doubt notification received");

        //Do any work necessary when indout notification is received
        
        //Declare done on the enlistment
        enlistment.Done();
    }
}

準備階段 (第一階段)

在收到來自應用程式的 Commit 要求之後,交易管理員會呼叫每個登記資源上的 Prepare 方法來開始所有登記參與者的準備階段,以取得每個資源對交易的投票。

負責實作 IEnlistmentNotification 介面的資源管理員應該先實作 Prepare 方法,如下列簡單範例所示。

public void Prepare(PreparingEnlistment preparingEnlistment)
{
     Console.WriteLine("Prepare notification received");
     //Perform work

     Console.Write("reply with prepared? [Y|N] ");
     c = Console.ReadKey();
     Console.WriteLine();
 
     //If work finished correctly, reply with prepared
     if ((c.KeyChar == 'Y') || (c.KeyChar == 'y'))
     {
          preparingEnlistment.Prepared();
          break;
     }

     // otherwise, do a ForceRollback
     else if ((c.KeyChar == 'N') || (c.KeyChar == 'n'))
     {
          preparingEnlistment.ForceRollback();
          break;
     }
}

當永久性資源管理員收到此呼叫,它應該將交易的復原資訊 (可藉由擷取 RecoveryInformation 屬性而得) 以及完成交易認可所需的任何資訊記錄下來。由於 RM 可在工作執行緒上進行這項作業,因此您不需要透過 Prepare 方法來做這件事。

當 RM 完整準備工作時,就會呼叫 PreparedForceRollback 方法來投票認可或復原交易。請注意,PreparingEnlistment 類別會繼承來自 Enlistment 類別的 Done 方法。如果您在準備階段於 PreparingEnlistment 回呼上呼叫此方法,則它會通知 TM 已登記為唯讀 (亦即,資源管理員可以讀取但無法更新交易保護的資料) 而且 RM 也將無法繼續收到來自交易管理員有關第二階段交易結果的任何告知。

當所有資源管理員都投票選擇 Prepared 時,應用程式將被告知已經成功認可交易。

交易階段 (第二階段)

在交易的第二階段,如果交易管理員收到來自所有資源管理員的準備成功消息 (所有資源管理員在第一階段結束時都叫用了 Prepared),則它會為每個資源管理員叫用 Commit 方法。資源管理員會接著進行永久性變更並完成交易認可動作。

如果有任何資源管理員在第一階段中報告準備失敗,則交易管理員會為每個資源管理員叫用 Rollback 方法,並向應用程式指出交易認可失敗之處。

因此,您的資源管理員應該實作下列方法。

public void Commit (Enlistment enlistment)
{
     // Do any work necessary when commit notification is received

     // Declare done on the enlistment
     enlistment.Done();
}

public void Rollback (Enlistment enlistment)
{
     // Do any work necessary when rollback notification is received

     // Declare done on the enlistment  
     enlistment.Done();  
}

RM 應該依據告知型別執行任何必要的工作以完成交易,並呼叫 Enlistment 參數上的 Done 方法,告知 TM 已完成交易。這項工作可在工作執行緒上完成。請注意,第二階段告知會發生並內嵌在第一階段中呼叫 Prepared 方法的同一個執行緒上。因此,當您預期在收到第二階段告知之前會完成 Prepared 呼叫時,請勿在此呼叫之後執行任何工作 (例如,釋放鎖定)。

實作 InDoubt

最後,您應該為變動性資源管理員實作 InDoubt 方法。如果交易管理員失去與一或多個參與者的聯繫而無法得知其個別狀態時,就會呼叫此方法。如果發生這種情況,不管是否有任何交易參與者仍舊維持在不一致的狀態,您都應該將此事實記錄下來以便稍後進一步探究原因。

public void InDoubt (Enlistment enlistment)
{
     // log this
     enlistment.Done();
}

單一階段交易認可最佳化

在執行階段使用單一階段交易認可通訊協定會比較有效率,因為所有的更新不需要任何個別的協調作業就可完成。如需此通訊協定的詳細資訊,請參閱使用單一階段交易認可和可提升單一階段告知進行最佳化

請參閱

概念

使用單一階段交易認可和可提升單一階段告知進行最佳化
將資源登記成為交易中的參與者

Footer image

Copyright © 2007 by Microsoft Corporation. All rights reserved.