SqlTransaction transações de banco de dados

Transação (Transaction): um conjunto de operações SQL executadas de forma atômica. Ou todas são confirmadas com Commit, ou todas são desfeitas em caso de falha com Rollback, atendendo às propriedades ACID.
No .NET Framework/.NET a implementação é feita com SqlTransaction, exclusivo para o SQL Server.

Pontos importantes do fluxo:

  1. Abrir a conexão com o banco de dados conn.Open()
  2. Iniciar a transação pela conexão conn.BeginTransaction()
  3. Vincular o objeto de transação na propriedade SqlCommand.Transaction
  4. Executar várias instruções SQL em lote
  5. Sem exceções: tx.Commit(); capturar exceções: tx.Rollback()

Exemplo

O código original não tem a lógica de rollback dentro do bloco catch. Veja a versão completa e funcional:

public static int ExecuteSqlTran(List<string> SQLStringList)
{
    using (SqlConnection conn = new SqlConnection(connectionString))
    {
        conn.Open();
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = conn;
        SqlTransaction tx = conn.BeginTransaction();
        cmd.Transaction = tx;
        try
        {
            int count = 0;
            for (int n = 0; n < SQLStringList.Count; n++)
            {
                string strsql = SQLStringList[n];
                if (strsql.Trim().Length > 1)
                {
                    cmd.CommandText = strsql;
                    count += cmd.ExecuteNonQuery();
                }
            }
            tx.Commit(); // Confirma a transação se tudo der certo
            return count;
        }
        catch (Exception ex)
        {
            tx.Rollback(); // Desfaz tudo se qualquer instrução falhar
            throw ex; // Relança a exceção para que camadas superiores saibam da falha
        }
    }
}Code language: C# (cs)

Essa versão monta as instruções SQL concatenando strings e possui risco de injeção de SQL. Ela serve para estudar o funcionamento das transações, mas em projetos de produção dê preferência às consultas parametrizadas.

Exemplo de transação com consultas parametrizadas

Inserimos dados dentro de um laço, usando SqlParameter para evitar injeções. Pontos cruciais:

  1. No fim de cada repetição chame sqlCom.Parameters.Clear() para remover parâmetros antigos e evitar erros de acúmulo
  2. Reutilize a mesma instância do objeto SqlCommand, alterando apenas CommandText e os parâmetros
SqlCommand sqlCom = new SqlCommand();
sqlCom.Connection = conn;
SqlTransaction st = conn.BeginTransaction();
sqlCom.Transaction = st;
int res = 0;
try
{
    for (int i = 0; i < 10; i++)
    {
        sqlCom.CommandText = "INSERT INTO [dbo].[Article]([Title])VALUES(@Title)";
        SqlParameter param = new SqlParameter("@Title", SqlDbType.NVarChar, 250);
        param.Value = i + "Este é um novo título" + DateTime.Now;
        sqlCom.Parameters.Add(param);
        res += sqlCom.ExecuteNonQuery();
        sqlCom.Parameters.Clear(); // Limpa os parâmetros para a próxima iteração
    }
    st.Commit();
}
catch (Exception)
{
    st.Rollback(); // Reverte todas as alterações se ocorrer uma exceção
}Code language: C# (cs)

1. Regras obrigatórias que devem ser seguidas

  • O método BeginTransaction() deve ser chamado após abrir a conexão com Open
  • É preciso definir a propriedade Transaction no SqlCommand, senão uma exceção será lançada
  • Depois de chamar Commit() ou Rollback() a transação é encerrada automaticamente, não faça chamadas repetidas

Observações adicionais

  • No .NET Core/.NET 5+, recomenda‑se usar o bloco using para liberar o SqlTransaction de forma automática
  • Para cenários com grandes volumes de SQL em lote, considere usar SqlBulkCopy, ele tem desempenho superior ao ExecuteNonQuery dentro de laços
  • O SqlTransaction não suporta transações entre bancos diferentes. Para isso você vai precisar de transações distribuídas com TransactionScope

SqlTransaction transações de banco de dados

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *