Partilhar via


TransactionScope.Dispose Método

Definição

Encerra o escopo da transação.

public:
 virtual void Dispose();
public void Dispose ();
abstract member Dispose : unit -> unit
override this.Dispose : unit -> unit
Public Sub Dispose ()

Implementações

Exemplos

O exemplo a seguir demonstra como usar a TransactionScope classe para definir um bloco de código para participar de uma transação.

// This function takes arguments for 2 connection strings and commands to create a transaction 
// involving two SQL Servers. It returns a value > 0 if the transaction is committed, 0 if the 
// transaction is rolled back. To test this code, you can connect to two different databases 
// on the same server by altering the connection string, or to another 3rd party RDBMS by 
// altering the code in the connection2 code block.
static public int CreateTransactionScope(
    string connectString1, string connectString2,
    string commandText1, string commandText2)
{
    // Initialize the return value to zero and create a StringWriter to display results.
    int returnValue = 0;
    System.IO.StringWriter writer = new System.IO.StringWriter();

    try
    {
        // Create the TransactionScope to execute the commands, guaranteeing
        // that both commands can commit or roll back as a single unit of work.
        using (TransactionScope scope = new TransactionScope())
        {
            using (SqlConnection connection1 = new SqlConnection(connectString1))
            {
                // Opening the connection automatically enlists it in the 
                // TransactionScope as a lightweight transaction.
                connection1.Open();

                // Create the SqlCommand object and execute the first command.
                SqlCommand command1 = new SqlCommand(commandText1, connection1);
                returnValue = command1.ExecuteNonQuery();
                writer.WriteLine("Rows to be affected by command1: {0}", returnValue);

                // If you get here, this means that command1 succeeded. By nesting
                // the using block for connection2 inside that of connection1, you
                // conserve server and network resources as connection2 is opened
                // only when there is a chance that the transaction can commit.   
                using (SqlConnection connection2 = new SqlConnection(connectString2))
                {
                    // The transaction is escalated to a full distributed
                    // transaction when connection2 is opened.
                    connection2.Open();

                    // Execute the second command in the second database.
                    returnValue = 0;
                    SqlCommand command2 = new SqlCommand(commandText2, connection2);
                    returnValue = command2.ExecuteNonQuery();
                    writer.WriteLine("Rows to be affected by command2: {0}", returnValue);
                }
            }

            // The Complete method commits the transaction. If an exception has been thrown,
            // Complete is not  called and the transaction is rolled back.
            scope.Complete();
        }
    }
    catch (TransactionAbortedException ex)
    {
        writer.WriteLine("TransactionAbortedException Message: {0}", ex.Message);
    }

    // Display messages.
    Console.WriteLine(writer.ToString());

    return returnValue;
}
'  This function takes arguments for 2 connection strings and commands to create a transaction 
'  involving two SQL Servers. It returns a value > 0 if the transaction is committed, 0 if the 
'  transaction is rolled back. To test this code, you can connect to two different databases 
'  on the same server by altering the connection string, or to another 3rd party RDBMS  
'  by altering the code in the connection2 code block.
Public Function CreateTransactionScope( _
  ByVal connectString1 As String, ByVal connectString2 As String, _
  ByVal commandText1 As String, ByVal commandText2 As String) As Integer

    ' Initialize the return value to zero and create a StringWriter to display results.
    Dim returnValue As Integer = 0
    Dim writer As System.IO.StringWriter = New System.IO.StringWriter

    Try
    ' Create the TransactionScope to execute the commands, guaranteeing
    '  that both commands can commit or roll back as a single unit of work.
        Using scope As New TransactionScope()
            Using connection1 As New SqlConnection(connectString1)
                ' Opening the connection automatically enlists it in the 
                ' TransactionScope as a lightweight transaction.
                connection1.Open()

                ' Create the SqlCommand object and execute the first command.
                Dim command1 As SqlCommand = New SqlCommand(commandText1, connection1)
                returnValue = command1.ExecuteNonQuery()
                writer.WriteLine("Rows to be affected by command1: {0}", returnValue)

                ' If you get here, this means that command1 succeeded. By nesting
                ' the using block for connection2 inside that of connection1, you
                ' conserve server and network resources as connection2 is opened
                ' only when there is a chance that the transaction can commit.   
                Using connection2 As New SqlConnection(connectString2)
                    ' The transaction is escalated to a full distributed
                    ' transaction when connection2 is opened.
                    connection2.Open()

                    ' Execute the second command in the second database.
                    returnValue = 0
                    Dim command2 As SqlCommand = New SqlCommand(commandText2, connection2)
                    returnValue = command2.ExecuteNonQuery()
                    writer.WriteLine("Rows to be affected by command2: {0}", returnValue)
                End Using
            End Using

        ' The Complete method commits the transaction. If an exception has been thrown,
        ' Complete is called and the transaction is rolled back.
        scope.Complete()
        End Using
    Catch ex As TransactionAbortedException
        writer.WriteLine("TransactionAbortedException Message: {0}", ex.Message)
    End Try

    ' Display messages.
    Console.WriteLine(writer.ToString())

    Return returnValue
End Function

Comentários

Chamar esse método marca o fim do escopo da transação. Se o TransactionScope objeto criou a transação e Complete foi chamado no escopo, o TransactionScope objeto tenta confirmar a transação quando esse método é chamado. Nesse caso, esse método é bloqueado até que a primeira fase do processamento da transação seja concluída. A primeira fase termina depois que todos os gerenciadores de recursos e inscrições na transação votaram no resultado da transação e o TransactionManager decidiu confirmar ou anular a transação. A segunda fase do processamento é sempre assíncrona. Portanto, não há nenhuma garantia de que os dados apenas confirmados de dentro de uma determinada transação estarão imediatamente disponíveis posteriormente quando não estiverem usando outra transação para exibir esses dados.

O uso da construção C# using garante que esse método seja chamado mesmo se ocorrer uma exceção. Exceções que ocorrem depois de chamar esse método não podem afetar a transação. Esse método também restaura a transação de ambiente para o estado original. Um TransactionAbortedException será gerado se a transação não for realmente confirmada.

Como esse método é bloqueado até que a primeira fase do processamento de transações seja concluída, você deve ter muito cuidado ao usar esse método em um aplicativo WinForm (Windows Form) ou um deadlock pode ocorrer. Se você chamar esse método dentro de um evento de Controle WinForm (por exemplo, clicar em um botão) e usar o método síncrono Invoke para direcionar o controle para executar algumas tarefas de interface do usuário (por exemplo, alterar cores) no meio do processamento da transação, ocorrerá um deadlock. Isso ocorre porque o Invoke método é síncrono e bloqueia o thread de trabalho até que o thread da interface do usuário conclua seu trabalho. No entanto, em nosso cenário, o thread da interface do usuário também está aguardando o thread de trabalho confirmar a transação. O resultado é que nenhum é capaz de prosseguir e o escopo aguarda indefinidamente a conclusão da Confirmação. Você deve usar BeginInvoke em vez de sempre que Invoke possível, porque ele é assíncrono e, portanto, menos propenso a deadlock.

Para obter mais informações sobre como esse método é usado, consulte o tópico Implementando uma transação implícita usando escopo de transação .

Aplica-se a

Confira também