COMMIT y ROLLBACK

COMMIT confirma todos los cambios realizados dentro de una transacción. ROLLBACK revierte todos los cambios y restaura los datos a su estado anterior.

START TRANSACTION

Inicia una transacción explícita. Todas las sentencias posteriores forman parte de la transacción hasta que se ejecute COMMIT o ROLLBACK.

-- Estas tres formas son equivalentes
START TRANSACTION;
BEGIN;
BEGIN WORK;

COMMIT

Confirma permanentemente todos los cambios realizados en la transacción.

START TRANSACTION;
 
INSERT INTO productos (nombre, precio, stock, categoria_id)
VALUES ('Producto de prueba', 99.99, 10, 1);
 
-- Los cambios se hacen permanentes
COMMIT;
 
-- Verificar
SELECT * FROM productos WHERE nombre = 'Producto de prueba';
idnombrepreciostockcategoria_id
...Producto de prueba99.99101
-- Limpieza
DELETE FROM productos WHERE nombre = 'Producto de prueba';

ROLLBACK

Revierte todos los cambios realizados en la transacción.

-- Ver stock actual
SELECT id, nombre, stock FROM productos WHERE id = 1;
idnombrestock
1iPhone 15 Pro50
START TRANSACTION;
 
UPDATE productos SET stock = 0 WHERE id = 1;
 
-- Verificar el cambio (dentro de la transacción)
SELECT stock FROM productos WHERE id = 1;
stock
0
-- Revertir
ROLLBACK;
 
-- El stock vuelve al valor original
SELECT stock FROM productos WHERE id = 1;
stock
50

Visibilidad de los cambios

Los cambios dentro de una transacción solo son visibles para la conexión que los realiza, hasta que se confirmen con COMMIT.

Conexión 1:

START TRANSACTION;
UPDATE productos SET precio = 999.99 WHERE id = 1;
-- El precio cambió para esta conexión
SELECT precio FROM productos WHERE id = 1;
-- Resultado: 999.99

Conexión 2 (simultánea):

-- Ve el precio original (la transacción no se ha confirmado)
SELECT precio FROM productos WHERE id = 1;
-- Resultado: 1299.99

Conexión 1:

COMMIT;
-- Ahora el cambio es visible para todos

Ejemplo: transferencia de fondos

CREATE TABLE cuentas (
    id INT AUTO_INCREMENT PRIMARY KEY,
    titular VARCHAR(100),
    saldo DECIMAL(10,2)
);
 
INSERT INTO cuentas (titular, saldo)
VALUES ('Alicia', 1000.00), ('Roberto', 500.00);
DELIMITER //
 
CREATE PROCEDURE sp_transferir(
    IN p_origen INT,
    IN p_destino INT,
    IN p_monto DECIMAL(10,2)
)
BEGIN
    DECLARE v_saldo DECIMAL(10,2);
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        ROLLBACK;
        SELECT 'Error: transferencia cancelada' AS resultado;
    END;
 
    START TRANSACTION;
 
    -- Verificar saldo (FOR UPDATE bloquea la fila)
    SELECT saldo INTO v_saldo
    FROM cuentas WHERE id = p_origen
    FOR UPDATE;
 
    IF v_saldo < p_monto THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Saldo insuficiente';
    END IF;
 
    -- Debitar origen
    UPDATE cuentas SET saldo = saldo - p_monto WHERE id = p_origen;
 
    -- Acreditar destino
    UPDATE cuentas SET saldo = saldo + p_monto WHERE id = p_destino;
 
    COMMIT;
    SELECT 'Transferencia exitosa' AS resultado;
END //
 
DELIMITER ;
-- Transferir 200 de Alicia a Roberto
CALL sp_transferir(1, 2, 200.00);
resultado
Transferencia exitosa
SELECT * FROM cuentas;
idtitularsaldo
1Alicia800.00
2Roberto700.00
-- Intentar transferir más de lo disponible
CALL sp_transferir(1, 2, 5000.00);
resultado
Error: transferencia cancelada
-- Los saldos no cambiaron
SELECT * FROM cuentas;
idtitularsaldo
1Alicia800.00
2Roberto700.00

COMMIT y ROLLBACK con autocommit

Cuando autocommit = 1 (predeterminado), cada sentencia individual se confirma automáticamente. Para agrupar sentencias, usa START TRANSACTION:

-- Con autocommit activado
-- Este INSERT se confirma automáticamente
INSERT INTO productos (nombre, precio, stock, categoria_id)
VALUES ('Auto 1', 10.00, 1, 1);
 
-- Pero dentro de una transacción explícita, no
START TRANSACTION;
 
INSERT INTO productos (nombre, precio, stock, categoria_id)
VALUES ('Auto 2', 20.00, 1, 1);
 
ROLLBACK;
-- 'Auto 1' existe, 'Auto 2' no
-- Limpieza
DELETE FROM productos WHERE nombre IN ('Auto 1', 'Auto 2');

Desactivar autocommit

-- Desactivar autocommit para la sesión
SET autocommit = 0;
 
INSERT INTO productos (nombre, precio, stock, categoria_id)
VALUES ('Manual 1', 10.00, 1, 1);
 
INSERT INTO productos (nombre, precio, stock, categoria_id)
VALUES ('Manual 2', 20.00, 1, 1);
 
-- Nada se ha confirmado aún
-- Necesitas COMMIT explícito
COMMIT;
 
-- Reactivar autocommit
SET autocommit = 1;
-- Limpieza
DELETE FROM productos WHERE nombre IN ('Manual 1', 'Manual 2');

ROLLBACK parcial con SAVEPOINT

Para revertir solo parte de una transacción, usa SAVEPOINT:

START TRANSACTION;
 
INSERT INTO productos (nombre, precio, stock, categoria_id)
VALUES ('Paso 1', 10.00, 1, 1);
 
SAVEPOINT sp1;
 
INSERT INTO productos (nombre, precio, stock, categoria_id)
VALUES ('Paso 2', 20.00, 1, 1);
 
-- Revertir solo el paso 2
ROLLBACK TO sp1;
 
COMMIT;
-- Solo 'Paso 1' se guardó
-- Limpieza
DELETE FROM productos WHERE nombre LIKE 'Paso%';

Los SAVEPOINTs se cubren en detalle en el siguiente artículo.

Errores comunes

ROLLBACK sin transacción activa

-- Sin START TRANSACTION, ROLLBACK no tiene efecto
INSERT INTO productos (nombre, precio, stock, categoria_id)
VALUES ('Ya confirmado', 10.00, 1, 1);
 
ROLLBACK; -- No revierte nada (autocommit ya confirmó el INSERT)
DELETE FROM productos WHERE nombre = 'Ya confirmado';

DDL dentro de transacciones

START TRANSACTION;
 
INSERT INTO productos (nombre, precio, stock, categoria_id)
VALUES ('DDL test', 10.00, 1, 1);
 
-- CREATE TABLE causa COMMIT implícito
CREATE TABLE temp_ddl (id INT);
 
-- El INSERT ya fue confirmado, ROLLBACK no lo revierte
ROLLBACK;
 
SELECT * FROM productos WHERE nombre = 'DDL test';
-- El registro existe
-- Limpieza
DROP TABLE IF EXISTS temp_ddl;
DELETE FROM productos WHERE nombre = 'DDL test';

Limpieza

DROP PROCEDURE IF EXISTS sp_transferir;
DROP TABLE IF EXISTS cuentas;

En el siguiente artículo veremos SAVEPOINT para crear puntos de restauración dentro de una transacción.

Escrito por Eduardo Lázaro