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. Este comportamiento depende del nivel de aislamiento configurado.

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. Puedes ver cómo funciona el autocommit en la introducción a las transacciones:

-- 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;

Las transacciones son la base de cualquier sistema que gestione operaciones de negocio críticas: transferencias, pedidos, facturación. En Andorra Dev diseñamos CRMs y ERPs donde cada operación financiera se ejecuta dentro de transacciones MySQL para garantizar la integridad de los datos.

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

Escrito por Eduardo Lázaro