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';| id | nombre | precio | stock | categoria_id |
|---|---|---|---|---|
| ... | Producto de prueba | 99.99 | 10 | 1 |
-- 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;| id | nombre | stock |
|---|---|---|
| 1 | iPhone 15 Pro | 50 |
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.99Conexión 2 (simultánea):
-- Ve el precio original (la transacción no se ha confirmado)
SELECT precio FROM productos WHERE id = 1;
-- Resultado: 1299.99Conexión 1:
COMMIT;
-- Ahora el cambio es visible para todosEjemplo: 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;| id | titular | saldo |
|---|---|---|
| 1 | Alicia | 800.00 |
| 2 | Roberto | 700.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;| id | titular | saldo |
|---|---|---|
| 1 | Alicia | 800.00 |
| 2 | Roberto | 700.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
