Transacciones en Transact SQL

Una transacción puede definirse como un conjunto de instrucciones que funcionan como una unidad, donde si una parte falla, todo el proceso falla en su totalidad, revirtiéndose todos los cambios producidos en la base de datos.

Para declarar una transacción partimos de la siguiente sintaxis:

BEGIN TRANSACTION

También será válida la sentencia acortada:

BEGIN TRAN

Una transacción, por tanto, valida todas las instrucciones que contiene como un único conjunto o unidad única de trabajo. Si todas las instrucciones funcionan, los cambios sobre la base de datos se confirman haciéndose permanentes. Si cualquier instrucción falla, todos los cambios deben revertirse.

A menudo y por tanto, es muy común que las transacciones contengan internamente estructuras de gestión de errores como TRY...CATH, para confirmar o revertir los cambios en base de datos. Si el código falla, se capturará el error en el CATCH y procederemos a revertir todos los cambios sobre la base de datos. Si todas las instrucciones del TRY funcionan correctamente, se procederá a guardar los cambios.

Si desea más información respectiva al control y manejo de errores, visitar la sección gestión de errores.

El control de guardado y revertimiento de los cambios respectivamente, se realizará a través de las siguientes instrucciones:

  • COMMIT TRANSACTION: Confirma y hace permanentes los cambios de base de datos si la transacción finaliza correctamente.

  • ROLLBACK TRANSACTION: Deshace y revierte los cambios de una transacción cuando se produce un error durante la misma, hasta el inicio de la transacción o hasta un punto de retorno dentro de ella.

  • SAVE TRANSACTION: Establece un punto de guardado dentro de una transacción.

Para entender bien el funcionamiento de una transacción y los conceptos de COMMIT y ROLLBACK, supongamos que queremos añadir dos nuevos clientes dentro de una transacción:

BEGIN TRANSACTION;
INSERT INTO Clientes VALUES ('Jesús',
                            'Nogales Calvo',
                            'Av. Manoteras 44',
                            NULL);
INSERT INTO Clientes VALUES ('Nuria',
                             NULL,
                             'Calle del sueño 98',
                             NULL);
COMMIT TRANSACTION;

Si ejecutamos el código de arriba, vemos que nos devuelve el siguiente mensaje de error:

No se puede insertar el valor NULL en la columna ‘apellidos’, tabla ‘tienda.dbo.Clientes’. La columna no admite valores NULL. Error de INSERT.

Sin embargo, si consultamos nuestra tabla Clientes podemos ver que ha insertado correctamente el primer registro referente a: Jesús Nogales Calvo:

idClientes nombre apellidos direccion cuenta
1019 Jesús Nogales Calvo Av. Manoteras 44 NULL

De este ejemplo, deducimos que no estamos haciendo un buen uso de la transacción, ya que no estamos contemplando los errores para deshacer los cambios con la instrucción ROLLBACK.

En el siguiente ejemplo, vamos a contemplar una gestión de errores y la instrucción ROLLBACK, para que en caso de que falle la inserción de un registro, falle el proceso en su totalidad.

BEGIN TRAN;
    BEGIN TRY
        INSERT INTO Clientes VALUES ('Alfonso',
                                     'Gutierrez Lan',
                                     'Av. Grande 23',
                                     NULL);
        INSERT INTO Clientes VALUES ('Nuria',
                                     NULL,
                                     'Calle del sueño 98',
                                     NULL);
        COMMIT TRAN;
    END TRY
    BEGIN CATCH
        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;
        ROLLBACK TRAN
    END CATCH;
ErrorNumber ErrorSeverity ErrorState ErrorProcedure ErrorLine ErrorMessage
515 16 2 NULL 4 No se puede insertar el valor NULL en la columna ‘apellidos’, tabla ‘tienda.dbo.Clientes’. La columna no admite valores NULL. Error de INSERT..

En este caso, aunque el primer INSERT INTO del registro: Alfonso Gutierrez Lan funcione correctamente, al fallar el segundo, capturamos el error en el CATCH y hacemos ROLLBACK de la transacción. Por tanto, si consultamos la tabla Clientes podemos comprobar que no se ha insertado ningún registro.