Transações locais

As transações do ADO.NET são usadas quando você deseja associar várias tarefas para que elas sejam executadas como uma só unidade de trabalho. Por exemplo, imagine que um aplicativo executa duas tarefas. Primeiro, ele atualiza uma tabela com informações sobre pedidos. Em seguida, ele atualiza uma tabela que contém informações de inventário, debitando os itens pedidos. Se uma das tarefas falhar, as duas atualizações serão revertidas.

Determinando o tipo de transação

Uma transação é considerada local quando é monofásica e é tratada diretamente pelo banco de dados. Uma transação é considerada distribuída quando é coordenada por um monitor de transação e usa mecanismos à prova de falhas (como o protocolo 2PC) na resolução das transações.

Cada provedor de dados do .NET Framework tem seu próprio objeto Transaction para executar transações locais. Se você precisar executar uma transação em um banco de dados do SQL Server, selecione uma transação System.Data.SqlClient. Para uma transação Oracle, use o provedor System.Data.OracleClient. Além disso, há uma classe DbTransaction que está disponível para a criação de um código independente de provedor que exige transações.

Observação

As transações são mais eficientes quando são executadas no servidor. Se você estiver trabalhando com um banco de dados do SQL Server que faz uso extensivo de transações explícitas, considere criá-las como procedimentos armazenados usando a instrução Transact-SQL BEGIN TRANSACTION.

Executando uma transação com uma única conexão

No ADO.NET, você controla as transações com o objeto Connection. É possível iniciar uma transação local com o método BeginTransaction. Depois de iniciar uma transação, você pode inscrever um comando nessa transação com a propriedade Transaction de um objeto Command. Em seguida, você poderá confirmar ou reverter todas as modificações feitas na fonte de dados com base no êxito ou na falha dos componentes de transação.

Observação

O método EnlistDistributedTransaction não deve ser usado para uma transação local.

O escopo da transação é limitado à conexão. O exemplo a seguir executa uma transação explícita que consiste em dois comandos separados no bloco try. Os comandos executam as instruções INSERT na tabela Production.ScrapReason do banco de dados de exemplo AdventureWorks do SQL Server, as quais são confirmadas se nenhuma exceção for gerada. O código no bloco catch reverterá a transação se uma exceção for lançada. Se a transação for anulada ou a conexão for fechada antes de a transação ser concluída, a transação será automaticamente revertida.

Exemplo

Siga estas etapas para executar uma transação.

  1. Chame o método BeginTransaction do objeto SqlConnection para marcar o início da transação. O método BeginTransaction retorna uma referência à transação. Essa referência é atribuída aos objetos SqlCommand inscritos na transação.

  2. Atribua o objeto Transaction à propriedade Transaction de SqlCommand a ser executado. Se um comando for executado em uma conexão com uma transação ativa, e o objeto Transaction não tiver sido atribuído à propriedade Transaction do objeto Command, uma exceção será gerada.

  3. Execute os comandos necessários.

  4. Chame o método Commit do objeto SqlTransaction para concluir a transação, ou chame o método Rollback para finalizar a transação. Se a conexão for fechada ou descartada antes do método Commit ou Rollback ser executado, a transação será revertida.

O exemplo de código a seguir demonstra a lógica transacional usando ADO.NET com o Microsoft SQL Server.

using (SqlConnection connection = new(connectionString))
{
    connection.Open();

    // Start a local transaction.
    SqlTransaction sqlTran = connection.BeginTransaction();

    // Enlist a command in the current transaction.
    SqlCommand command = connection.CreateCommand();
    command.Transaction = sqlTran;

    try
    {
        // Execute two separate commands.
        command.CommandText =
          "INSERT INTO Production.ScrapReason(Name) VALUES('Wrong size')";
        command.ExecuteNonQuery();
        command.CommandText =
          "INSERT INTO Production.ScrapReason(Name) VALUES('Wrong color')";
        command.ExecuteNonQuery();

        // Commit the transaction.
        sqlTran.Commit();
        Console.WriteLine("Both records were written to database.");
    }
    catch (Exception ex)
    {
        // Handle the exception if the transaction fails to commit.
        Console.WriteLine(ex.Message);

        try
        {
            // Attempt to roll back the transaction.
            sqlTran.Rollback();
        }
        catch (Exception exRollback)
        {
            // Throws an InvalidOperationException if the connection
            // is closed or the transaction has already been rolled
            // back on the server.
            Console.WriteLine(exRollback.Message);
        }
    }
}
Using connection As New SqlConnection(connectionString)
    connection.Open()

    ' Start a local transaction.
    Dim sqlTran As SqlTransaction = connection.BeginTransaction()

    ' Enlist a command in the current transaction.
    Dim command As SqlCommand = connection.CreateCommand()
    command.Transaction = sqlTran

    Try
        ' Execute two separate commands.
        command.CommandText = _
          "INSERT INTO Production.ScrapReason(Name) VALUES('Wrong size')"
        command.ExecuteNonQuery()
        command.CommandText = _
          "INSERT INTO Production.ScrapReason(Name) VALUES('Wrong color')"
        command.ExecuteNonQuery()

        ' Commit the transaction
        sqlTran.Commit()
        Console.WriteLine("Both records were written to database.")

    Catch ex As Exception
        ' Handle the exception if the transaction fails to commit.
        Console.WriteLine(ex.Message)

        Try
            ' Attempt to roll back the transaction.
            sqlTran.Rollback()

        Catch exRollback As Exception
            ' Throws an InvalidOperationException if the connection 
            ' is closed or the transaction has already been rolled 
            ' back on the server.
            Console.WriteLine(exRollback.Message)
        End Try
    End Try
End Using

Confira também