SqlTransaction transacciones de base de datos

Transacción (Transaction): conjunto de operaciones SQL que se ejecutan de forma atómica. O bien todo se confirma mediante Commit, o bien todo se deshace si ocurre un fallo con Rollback, cumpliendo las propiedades ACID.
En .NET Framework/.NET se implementa mediante SqlTransaction, componente exclusivo para SQL Server.

Puntos clave del flujo:

  1. Abrir la conexión de base de datos conn.Open()
  2. Iniciar la transacción a través de la conexión conn.BeginTransaction()
  3. Asociar el objeto de transacción a SqlCommand.Transaction
  4. Ejecutar varias sentencias SQL por lotes
  5. Sin excepciones: tx.Commit(); capturar excepciones: tx.Rollback()

Ejemplo

El código original no incluye la lógica de deshacer dentro del bloque catch. Aquí tienes la versión completa lista para ejecutar:

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(); // Si todo sale bien, confirmamos la transacción
            return count;
        }
        catch (Exception ex)
        {
            tx.Rollback(); // Si falla alguna sentencia, deshacemos todos los cambios
            throw ex; // Volvemos a lanzar la excepción para que la capa superior detecte el error
        }
    }
}Lenguaje del código: C# (cs)

Esta implementación concatena cadenas SQL directamente y expone el sistema a inyecciones SQL. Es útil para entender cómo funcionan las transacciones, pero en proyectos reales debes optar siempre por las consultas parametrizadas.

Ejemplo de transacción con consultas parametrizadas

Insertamos registros en bucle y usamos SqlParameter para prevenir inyecciones. Detalles importantes:

  1. Al final de cada iteración llama a sqlCom.Parameters.Clear() para borrar parámetros antiguos y evitar errores por acumulación
  2. Reutilizamos la misma instancia de SqlCommand, solo modificamos CommandText y sus 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 es un nuevo título" + DateTime.Now;
        sqlCom.Parameters.Add(param);
        res += sqlCom.ExecuteNonQuery();
        sqlCom.Parameters.Clear(); // Limpiamos parámetros para la siguiente vuelta
    }
    st.Commit();
}
catch (Exception)
{
    st.Rollback(); // Si salta una excepción, revertimos todo
}Lenguaje del código: C# (cs)

1. Reglas obligatorias que debes cumplir

  • La llamada a BeginTransaction() debe hacerse después de abrir la conexión con Open
  • Es obligatorio asignar la propiedad Transaction en SqlCommand, de lo contrario se lanzará una excepción
  • Tras ejecutar Commit() o Rollback() la transacción finaliza automáticamente, no puedes invocarlos de nuevo

Otros apuntes

  • En .NET Core/.NET 5+, se recomienda usar la sentencia using para liberar automáticamente el objeto SqlTransaction
  • Para procesar lotes muy grandes de sentencias SQL, valora el uso de SqlBulkCopy, rinde mejor que ejecutar ExecuteNonQuery dentro de bucles
  • SqlTransaction no sirve para transacciones que abarquen varias bases de datos. En esos casos necesitas transacciones distribuidas mediante TransactionScope

SqlTransaction transacciones de base de datos

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *