Transações

Transações são necessárias quando realizamos um conjunto de operações em um determinado recursos distribuído (banco de dados, serviço  de mensageria, serviço de gerenciamento de arquivos, etc) e queremos garantir a completude deste conjunto de operações ao seu término, evitando que qualquer possível erro durante a execução do conjunto de operações deixe os recursos distribuídos inconsistentes.

cjta_wstran1

As transações devem garantir um conjunto de características, tais características são chamadas de ACID:
– Atomicidade: Uma transação é uma unidade atômica de processamento, ou ela será executada em sua totalidade ou não será de modo nenhum.
Consistência: Uma transação será preservadora de consistência se sua execução completa fizer o recurso distribuído passe de um estado consistente para outro.
Isolamento: Uma transação deve ser executada como se estivesse isolada das demais. A execução de uma transação não deve sofrer interferências de quaisquer outra transação concorrente.
Durabilidade: As mudanças aplicadas ao recurso distribuído por uma transação devem ser persistidas neste recurso distribuído ao término da transação. Essas mudanças não devem ser perdidas em razão de uma falha.

Podemos utilizar as transações de diferentes maneiras. Vou exemplificar três modos:

1 – Dentro de uma procedure de banco de dados: quando for necessária a manipulação de diferentes tabelas dentro de um mesmo bloco de código, então é recomendado o uso de transações em procedures, como abaixo.

-- ABRE UMA TRANSAÇÃO
BEGIN TRANSACTION;

BEGIN TRY

    -- COMANDOS SQL

END TRY
BEGIN CATCH

    -- SELECIONA DADOS DO ERRO
    SELECT 
        ERROR_NUMBER() AS ErrorNumber
        ,ERROR_SEVERITY() AS ErrorSeverity
        ,ERROR_STATE() AS ErrorState
        ,ERROR_PROCEDURE() AS ErrorProcedure
        ,ERROR_LINE() AS ErrorLine
        ,ERROR_MESSAGE() AS ErrorMessage;

    -- SE EXISTIR UMA TRANSAÇÃO ENTÃO SERÁ FEITO O ROLLBACK
    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
END CATCH;

-- SE EXISTIR UM BLOCO DE TRANSAÇÃO ENTÃO É FEITO O COMMIT
IF @@TRANCOUNT > 0    
    COMMIT TRANSACTION;

2 – Dentro de um bloco de código que faça acesso a um banco de dados: quando utilizarmos classe de acesso a dados do ADO.Net, é interessante que façamos uso de classes que herdem de DbTransaction (System.Data.Common), como a classe SqlTransaction, própria para o controle de transações que façam uso dos componentes do namespace System.Data.SqlClient.

// Abre a conexão com o banco de dados
using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();

    SqlCommand command = connection.CreateCommand();
    SqlTransaction transaction;

    // Cria o bloco de transação
    transaction = connection.BeginTransaction("SampleTransaction");

    // Associa a conexão e a transação com o comando a ser executado
    command.Connection = connection;
    command.Transaction = transaction;

    try
    {
        command.CommandText = "-- EXECUTA UM COMANDO";
        command.ExecuteNonQuery();
        command.CommandText = "-- EXECUTA UM COMANDO";
        command.ExecuteNonQuery();

        // Efetua o commit da transação
        transaction.Commit();
        Console.WriteLine("Ambos os registros foram registrados no banco de dados");
    }
    catch (Exception ex)
    {
        Console.WriteLine("Commit Exception Type: {0}", ex.GetType());
        Console.WriteLine("  Message: {0}", ex.Message);

        // Realiza o rollback da transação caso alguma falha ocorra
        transaction.Rollback();
        
    }
}

3 – Dentro de um bloco de código que trabalhe com diferentes recursos compartilhados: quando fizermos uso de diferentes componentes distribuídos podemos aproveitar o Gerenciador de Transações Distribuídas do Windows (Microsoft Distributed Transaction Coordinator) para nos auxiliar no funcionamento de nossa transação. Tecnologias como: Windows Message Queue, Microsoft SQL Server, Oracle DataBases, WebSphere Message Queue, BizTalk Servers e outros fazem integração com o Gerenciador de Transações Distribuídas do Windows.

// using System.Transactions;
// Fazer referência a dll System.Transactions.dll

try
{
    // Cria o bloco de transação.
    using (TransactionScope scope = new TransactionScope())
    {
        using (SqlConnection connection1 = new SqlConnection(connectString1))
        {
            // Abre a conexão com o banco de dados 1
            connection1.Open();

            // Cria o objeto de comando para execução da primeira instrução no banco de dados
            SqlCommand command1 = new SqlCommand(commandText1, connection1);
            returnValue = command1.ExecuteNonQuery();
            writer.WriteLine("Linhas afetadas pelo comando 1: {0}", returnValue);

            // Abre outra conexão, com outro banco de dados. 
            using (SqlConnection connection2 = new SqlConnection(connectString2))
            {
                // Abre a conexão com o banco de dados 2
                connection2.Open();

                // Executa um segundo comando em outro banco de dados
                returnValue = 0;
                SqlCommand command2 = new SqlCommand(commandText2, connection2);
                returnValue = command2.ExecuteNonQuery();
                writer.WriteLine("Linhas afetadas pelo comando 2: {0}", returnValue);
            }
        }

        // Quando o procedimento estiver completo, então a transação é concluída
        scope.Complete();

    }

}
catch (TransactionAbortedException ex)
{
    writer.WriteLine("TransactionAbortedException Message: {0}", ex.Message);
}
catch (ApplicationException ex)
{
    writer.WriteLine("ApplicationException Message: {0}", ex.Message);
}

Obs.: Sempre que utilizo transações, com Entity Framework ou Enterprise Library, faço uso do TransactionScope.

Referências:

http://msdn.microsoft.com/pt-br/library/ms175976.aspx

http://msdn.microsoft.com/pt-br/library/system.transactions.transactionscope.aspx

http://msdn.microsoft.com/pt-br/library/system.data.common.dbtransaction.aspx

http://technet.microsoft.com/en-us/library/cc759136%28v=ws.10%29.aspx

Elmasri; Navathe; Sistemas de Banco de Dados; 4a Edição; Pearson – Addison Wesley

 

Por

MSc. Fernando Henrique Inocêncio Borba Ferreira

Microsoft Most Valuable Professional – Data Platform Development

Publicidade

2 comentários sobre “Transações

  1. Olá Fernando, ótimo assunto este de transação.

    Recentemente desenvolvi um WCF para controle de credito centralizado.
    Para tal utilizei TransactionScope, o interessante que utilizei tanto no client como no WCF com EF.
    Fiz teste com SQL Server e Oracle, tanto para o client como para o WCF e funcionou perfeitamente utilizando window 7 64bit no client e Windows Server 2008 no WCF.

    Quando o pessoal da qualidade testou utilizando o Windows XP 32bit o esquema não funcionou, retorna mensagem informando que é necessário habilitar o controle de transação no Windows.

    Procurei por todo lado na net como resolver e ainda não obtive uma solução.

    • Olá Leandro!
      Tudo beleza?
      O TransactionScope realmente é muito bacana de ser utilizado.
      Para habilitá-lo faça assim:
      – Abra o Painel de Controles, e vá em Ferramentas Administrativas
      – Acesse o atalho de “Component Services”
      – Expanda a árvore “Computers”
      – Clique com o botão direito em “My Computer” e clique em “Properties”
      – Vá até a aba “MSDTC”
      – Marque a opção “Use local coordinator”

      Obrigado por comentar!
      []s!

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.