Однофазная и многофазная фиксация транзакцииCommitting a Transaction in Single-Phase and Multi-Phase

Каждым используемым в транзакции ресурсом управляет диспетчер ресурсов, действия которого координируются диспетчером транзакций.Each resource used in a transaction is managed by a resource manager (RM), whose actions are coordinated by a transaction manager (TM). Прикрепление ресурсов как участников в разделе транзакции описывает, как ресурс (или несколько ресурсов) можно прикрепить к транзакции.The Enlisting Resources as Participants in a Transaction topic discusses how a resource (or multiple resources) can be enlisted in a transaction. В этом разделе также описывается порядок координации процесса фиксации транзакции между зачисленными ресурсами.This topic discusses how transaction commitment can be coordinated among enlisted resources.

В конце транзакции приложение запрашивает ее фиксацию или откат.At the end of the transaction, the application requests the transaction to be either committed or rolled back. Диспетчер транзакций должен исключить ситуации, в которых один из диспетчеров ресурсов голосует за фиксацию, а другие - за откат транзакции.The transaction manager must eliminate risks like some resource managers voting to commit while others voting to roll back the transaction.

Если транзакция включает несколько ресурсов, необходимо выполнить двухфазную фиксацию (2PC).If your transaction involves more than one resource, you must perform a two-phase commit (2PC). Протокол двухфазной фиксации (фаза подготовки и фаза фиксации) гарантирует, что при завершении транзакции все изменения, произведенные над всеми ресурсами, либо полностью фиксируются, либо полностью откатываются.The two-phase commit protocol (the prepare phase and the commit phase) ensures that when the transaction ends, all changes to all resources are either totally committed or fully rolled back. После завершения транзакции результат сообщается всем участникам.All the participants are then informed of the final result. Подробное описание протокола двухфазной фиксации см. в книге "обработка транзакций: основные понятия и методики (Morgan Кауфманн Series в управление данными Systems) ISBN: 1558601902", Джим серый.For a detailed discussion of the two-phase commit protocol, please consult the book "Transaction Processing : Concepts and Techniques (Morgan Kaufmann Series in Data Management Systems) ISBN:1558601902" by Jim Gray.

Кроме того, оптимизировать производительность транзакции можно путем участия в протоколе однофазной фиксации.You can also optimize your transaction's performance by taking part in the Single Phase Commit protocol. Дополнительные сведения см. в статье Оптимизация с использованием однофазных фиксаций и уведомления с одним этапом продвижения.For more information, see Optimization using Single Phase Commit and Promotable Single Phase Notification.

Если требуется только получение информации о результате транзакции без участия в голосовании, необходимо подписаться на событие TransactionCompleted.If you just want to be informed of a transaction's outcome, and do not want to participate in voting, you should register for the TransactionCompleted event.

Двухфазная фиксация (2PC)Two-phase Commit (2PC)

В первой фазе транзакции диспетчер транзакций опрашивает каждый ресурс, чтобы определить, следует ли выполнить фиксацию или откат транзакции.In the first transaction phase, the transaction manager queries each resource to determine whether a transaction should be committed or rolled back. Во второй фазе транзакции диспетчер транзакций уведомляет каждый ресурс о результате опроса, позволяя ресурсам выполнить необходимые операции очистки.In the second transaction phase, the transaction manager notifies each resource of the outcome of its queries, allowing it to perform any necessary cleanup.

Для участия в такой транзакции диспетчеру ресурсов необходимо реализовать интерфейс IEnlistmentNotification, который предоставляет методы, вызываемые диспетчером транзакций как уведомления при двухфазной фиксации.To participate in this kind of transaction, a resource manager must implement the IEnlistmentNotification interface, which provides methods that are called by the TM as notifications during a 2PC. Ниже представлен пример такой реализации.The following sample shows an example of such implementation.

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();
    }
}
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

Фаза подготовки (фаза 1)Prepare phase (Phase 1)

При получении запроса Commit от приложения диспетчер транзакций приступает к фазе подготовки всех зачисленных участников путем вызова метода Prepare для каждого зачисленного ресурса с целью получения голосов за результат транзакции.Upon receiving a Commit request from the application, the transaction manager begins the Prepare phase of all the enlisted participants by calling the Prepare method on each enlisted resource, in order to obtain each resource's vote on the transaction.

Диспетчеру ресурсов, реализующему интерфейс IEnlistmentNotification, сначала необходимо реализовать метод Prepare(PreparingEnlistment), как показано в следующем простом примере.Your resource manager that implements the IEnlistmentNotification interface should first implement the Prepare(PreparingEnlistment) method as the following simple example shows.

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) и всю необходимую информацию для завершения транзакции фиксацией.When the durable resource manager receives this call, it should log the transaction's recovery information (available by retrieving the RecoveryInformation property) and whatever information is necessary to complete the transaction on commit. Запись этой информации в рамках метода Prepare не требуется, поскольку диспетчер ресурсов может сделать это в рабочем потоке.This does not need to be performed within the Prepare method because the RM can do this on a worker thread.

После того, как диспетчер ресурсов завершил свои операции подготовки, ему необходимо проголосовать за фиксацию или откат путем вызова метода Prepared или ForceRollback.When the RM has finished its prepare work, it should vote to commit or roll back by calling the Prepared or ForceRollback method. Обратите внимание, что класс PreparingEnlistment наследует метод Done от класса Enlistment.Notice that the PreparingEnlistment class inherits a Done method from the Enlistment class. Если вызвать этот метод для обратного вызова PreparingEnlistment в фазе подготовки, он сообщает диспетчеру транзакций, что зачисленный ресурс доступен в режиме "только чтение" (т. е. диспетчеры ресурсов могут читать, но не могут изменять защищенные транзакцией данные), и диспетчер ресурсов не получает дальнейших уведомлений от диспетчера транзакций относительно результата транзакции в фазе 2.If you call this method on the PreparingEnlistment callback during the Prepare phase, it informs the TM that it is a Read-Only enlistment (that is, resource managers that can read but cannot update transaction-protected data) and the RM receives no further notifications from the transaction manager as to the outcome of the transaction in phase 2.

Приложение получает сведения об успешной подготовке к фиксации транзакции после того, как все диспетчеры ресурсов проголосуют с помощью метода Prepared.The application is told of the successful commitment of the transaction after all the resource managers vote Prepared.

Фаза фиксации (фаза 2)Commit phase (Phase 2)

Если во второй фазе транзакции диспетчер транзакций получает сведения об успешной подготовке от всех диспетчеров ресурсов (все диспетчеры ресурсов вызвали метод Prepared в конце фазы 1), он вызывает метод Commit для каждого диспетчера ресурсов.In the second phase of the transaction, if the transaction manager receives successful prepares from all the resource managers (all the resource managers have invoked Prepared at the end of phase 1), it invokes the Commit method for each resource manager. После этого диспетчеры ресурсов могут зафиксировать изменения.The resource managers can then make the changes durable and complete the commit.

Если в фазе 1 хотя бы от одного диспетчера ресурсов получено сообщение о том, что подготовку выполнить не удалось, диспетчер транзакций вызывает метод Rollback для каждого диспетчера ресурсов и сообщает приложению о сбое фиксации.If any resource manager reported a failure to prepare in phase 1, the transaction manager invokes the Rollback method for each resource manager and indicates the failure of the commit to the application.

Таким образом, используемому диспетчеру ресурсов необходимо реализовать следующие методы.Thus, your resource manager should implement the following methods.

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();
}  

Диспетчер ресурсов должен выполнить любые действия, необходимые для завершения транзакции в соответствии с типом уведомления, и затем информировать диспетчер транзакций о завершении транзакции, вызвав метод Done для параметра Enlistment.The RM should perform any work necessary to finish the transaction based on the notification type, and inform the TM that it has finished by calling Done method on the Enlistment parameter. Это может быть выполнено в рабочем потоке.This work can be done on a worker thread. Заметьте, что уведомления второго этапа могут быть встроены в тот же поток, который вызвал метод Prepared на первой фазе.Note that the phase 2 notifications can happen inline on the same thread that called the Prepared method in phase 1. Таким образом, после вызова метода Prepared не нужно выполнять никаких действий (например, снимать блокировки), которые должны были быть выполнены перед получением уведомлений второго этапа.As such, you should not do any work after the Prepared call (for example, releasing locks) that you would expect to have completed before receiving the phase 2 notifications.

Реализация метода InDoubtImplementing InDoubt

Наконец, необходимо реализовать метод InDoubt для диспетчера неустойчивых ресурсов.Finally, you should implement the InDoubt method for the volatile resource manager. Этот метод вызывается при потере контакта диспетчера транзакций с одним или несколькими участниками, в результате чего их состояние становится неизвестным.This method is called if the transaction manager loses contact with one or more participants, so their status is unknown. В этом случае необходимо сделать соответствующую запись в журнале, чтобы можно было позднее выяснить, остался ли кто-либо из участников транзакции в несогласованном состоянии.If this occurs, you should log this fact so that you can investigate later whether any of the transaction participants has been left in an inconsistent state.

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

Оптимизация однофазной фиксацииSingle Phase Commit Optimization

Протокол однофазной фиксации наиболее эффективен при использовании во время выполнения, поскольку все изменения производятся без какой-либо явной координации.The Single Phase Commit protocol is more efficient at run time because all updates are done without any explicit coordination. Дополнительные сведения об этом протоколе см. в статье Оптимизация с использованием однофазных фиксаций и уведомления с одним этапом продвижения.For more information on this protocol, see Optimization using Single Phase Commit and Promotable Single Phase Notification.

См. также разделSee also