Recrutando recursos como participantes de uma transação
Cada recurso que participa de uma transação é gerenciado por um gerente de recursos, cujas ações são coordenadas por um gerente de transações. A coordenação é feita através de notificações dadas aos assinantes que se inscreveram em uma transação através do gerente de transações.
Este tópico aborda como um recurso (ou vários recursos) pode ser alistado em uma transação, bem como os diferentes tipos de alistamento. O tópico Confirmando uma transação em fase única e multifásica aborda como o compromisso de transação pode ser coordenado entre os recursos alistados.
Recrutando recursos em uma transação
Para que um recurso participe de uma transação, ele deve se alistar na transação. A Transaction classe define um conjunto de métodos cujos nomes começam com Enlist que fornecem essa funcionalidade. Os diferentes métodos Enlist correspondem aos diferentes tipos de alistamento que um gerente de recursos pode ter. Especificamente, você usa os EnlistVolatile métodos para recursos voláteis e o EnlistDurable método para recursos duráveis. A durabilidade (ou, inversamente, a volatilidade) de um gestor de recursos refere-se ao facto de o gestor de recursos suportar a recuperação de falhas. Se um gerenciador de recursos oferecer suporte à recuperação de falhas, ele persistirá os dados para armazenamento durável durante a Fase 1 (preparação), de modo que, se o gerenciador de recursos ficar inativo, ele poderá se alistar novamente na transação após a recuperação e executar as ações adequadas com base nas notificações recebidas da TM. Em geral, os gerentes de recursos voláteis gerenciam recursos voláteis, como uma estrutura de dados na memória (por exemplo, um hashtable transacionado na memória), e os gerenciadores de recursos duráveis gerenciam recursos que têm um armazenamento de backup mais persistente (por exemplo, um banco de dados cujo armazenamento de backup é disco).
Para simplificar, depois de decidir se deseja usar o EnlistDurable método ou EnlistVolatile com base no suporte de durabilidade do seu recurso, você deve recrutar seu recurso para participar do Two Phase Commit (2PC) implementando a interface para seu IEnlistmentNotification gerenciador de recursos. Para obter mais informações sobre o 2PC, consulte Confirmando uma transação em monofásica e multifásica.
Um único participante pode se alistar para mais de um desses protocolos ligando EnlistDurable e EnlistVolatile várias vezes.
Alistamento durável
Os EnlistDurable métodos são usados para recrutar um gerente de recursos para participação na transação como um recurso durável. Espera-se que, se um gerenciador de recursos duráveis for derrubado no meio de uma transação, ele possa executar a recuperação uma vez que seja colocado on-line novamente, inscrevendo-se novamente (usando o método) em todas as transações nas quais foi participante e não concluiu a fase 2, e chamar RecoveryComplete assim que concluir o Reenlist processamento de recuperação. Para obter mais informações sobre recuperação, consulte Executando recuperação.
Todos os EnlistDurable métodos tomam um Guid objeto como seu primeiro parâmetro. O Guid é usado pelo gerenciador de transações para associar um alistamento durável a um gerenciador de recursos específico. Como tal, é imperativo que um gerente de recursos use consistentemente o mesmo Guid para se identificar, mesmo entre diferentes gerentes de recursos após a reinicialização, caso contrário, a recuperação pode falhar.
O segundo parâmetro do EnlistDurable método é uma referência ao objeto que o gerenciador de recursos implementa para receber notificações de transação. A sobrecarga usada informa ao gerenciador de transações se o gerenciador de recursos oferece suporte à otimização SPC (Single Phase Commit). Na maioria das vezes, você implementaria a IEnlistmentNotification interface para participar do Two-Phase Commit (2PC). No entanto, se você quiser otimizar o processo de confirmação, considere a implementação da interface para o ISinglePhaseNotification SPC. Para obter mais informações sobre o SPC, consulte Confirmando uma transação em monofásica e multifásica e Otimização usando confirmação monofásica e notificação monofásica promocional.
O terceiro parâmetro é uma EnlistmentOptions enumeração, cujo valor pode ser um None ou EnlistDuringPrepareRequired. Se o valor for definido como EnlistDuringPrepareRequired, o alistamento poderá recrutar gerentes de recursos adicionais ao receber a notificação Preparar do gerenciador de transações. No entanto, você deve estar ciente de que esse tipo de alistamento não é elegível para a otimização de Confirmação de Fase Única.
Alistamento volátil
Os participantes que gerenciam recursos voláteis, como um cache, devem se alistar usando os EnlistVolatile métodos. Esses objetos podem não ser capazes de obter o resultado de uma transação ou recuperar o estado de qualquer transação em que participem após uma falha do sistema.
Como dito anteriormente, um gerente de recursos faria um alistamento volátil se gerenciasse um recurso volátil na memória. Um dos benefícios do uso EnlistVolatile é que ele não força um escalonamento desnecessário da transação. Para obter mais informações sobre escalonamento de transações, consulte o tópico Escalonamento de gerenciamento de transações. A volatilidade do alistamento implica tanto uma diferença na forma como o alistamento é tratado pelo gestor de transações, como o que é esperado do gestor de recursos pelo gestor de transações. Isso ocorre porque um gerenciador de recursos voláteis não executa a recuperação. Os EnlistVolatile métodos não usam um Guid parâmetro, porque um gerenciador de recursos voláteis não executa a recuperação e não chamaria o Reenlist método que precisa de um Guidarquivo .
Assim como acontece com alistamentos duráveis, qualquer método de sobrecarga usado para recrutar indica ao gerenciador de transações se o gerenciador de recursos oferece suporte à otimização de confirmação monofásica. Como um gerenciador de recursos voláteis não pode executar a recuperação, nenhuma informação de recuperação é gravada para um alistamento volátil durante a fase Preparar. Portanto, chamar o RecoveryInformation método resulta em um InvalidOperationExceptionarquivo .
O exemplo a seguir mostra como inscrever tal objeto como um participante em uma transação usando o EnlistVolatile método.
static void Main(string[] args)
{
try
{
using (TransactionScope scope = new TransactionScope())
{
//Create an enlistment object
myEnlistmentClass myEnlistment = new myEnlistmentClass();
//Enlist on the current transaction with the enlistment object
Transaction.Current.EnlistVolatile(myEnlistment, EnlistmentOptions.None);
//Perform transactional work here.
//Call complete on the TransactionScope based on console input
ConsoleKeyInfo c;
while(true)
{
Console.Write("Complete the transaction scope? [Y|N] ");
c = Console.ReadKey();
Console.WriteLine();
if ((c.KeyChar == 'Y') || (c.KeyChar == 'y'))
{
scope.Complete();
break;
}
else if ((c.KeyChar == 'N') || (c.KeyChar == 'n'))
{
break;
}
}
}
}
catch (System.Transactions.TransactionException ex)
{
Console.WriteLine(ex);
}
catch
{
Console.WriteLine("Cannot complete transaction");
throw;
}
}
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 in doubt notification is received
//Declare done on the enlistment
enlistment.Done();
}
}
Public Shared Sub Main()
Try
Using scope As TransactionScope = New TransactionScope()
'Create an enlistment object
Dim myEnlistmentClass As New EnlistmentClass
'Enlist on the current transaction with the enlistment object
Transaction.Current.EnlistVolatile(myEnlistmentClass, EnlistmentOptions.None)
'Perform transactional work here.
'Call complete on the TransactionScope based on console input
Dim c As ConsoleKeyInfo
While (True)
Console.Write("Complete the transaction scope? [Y|N] ")
c = Console.ReadKey()
Console.WriteLine()
If (c.KeyChar = "Y") Or (c.KeyChar = "y") Then
scope.Complete()
Exit While
ElseIf ((c.KeyChar = "N") Or (c.KeyChar = "n")) Then
Exit While
End If
End While
End Using
Catch ex As TransactionException
Console.WriteLine(ex)
Catch
Console.WriteLine("Cannot complete transaction")
Throw
End Try
End Sub
End Class
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 in doubt notification is received
'Declare done on the enlistment
myEnlistment.Done()
End Sub
End Class
Otimizando o desempenho
A Transaction classe também fornece o EnlistPromotableSinglePhase método para recrutar um alistamento monofásico promocional (PSPE). Isso permite que um gerenciador de recursos duráveis (RM) hospede e "possua" uma transação que pode ser escalada posteriormente para ser gerenciada pelo MSDTC, se necessário. Para obter mais informações sobre isso, consulte Otimização usando confirmação monofásica e Notificação monofásica promocional.