Transacciones: BEGIN, COMMIT y ROLLBACK
Lección 05 · SQL avanzado
Transacciones: BEGIN, COMMIT y ROLLBACK
Imagina que estás transfiriendo dinero de una cuenta bancaria a otra. Son dos operaciones: restar de una cuenta y sumar a la otra. ¿Qué pasa si la primera se ejecuta pero la segunda falla? Tendrías dinero que desaparece. Las transacciones existen para evitar exactamente eso.
Diagrama: flujo vertical de transacción: badge BEGIN (“Se abre la transacción”) → caja “Operaciones agrupadas” (INSERT, UPDATE, DELETE) → pregunta “¿Todo correcto?” → rama “Sí” hacia COMMIT (“Cambios guardados permanentemente”) y rama “No” hacia ROLLBACK (“Todo vuelve al estado original”).
¿Qué es una transacción?
Una transacción es un grupo de operaciones SQL que se ejecutan como una unidad indivisible. O se ejecutan todas correctamente, o no se ejecuta ninguna.
Este principio se conoce como atomicidad, y es la primera letra de las propiedades ACID que garantizan la fiabilidad de las bases de datos. ACID es un acrónimo en inglés, por lo que sus letras provienen de los términos originales:
| Propiedad | Significado |
|---|---|
| Atomicity (atomicidad) | Todo o nada. Si una operación falla, se deshacen todas. |
| Consistency (consistencia) | La base de datos pasa de un estado válido a otro estado válido. |
| Isolation (aislamiento) | Las transacciones concurrentes no se interfieren entre sí. |
| Durability (durabilidad) | Una vez confirmada, la transacción sobrevive a fallos del sistema. |
Sintaxis básica
BEGIN TRANSACTION;
-- Operaciones que forman la transacción
UPDATE cuentas SET saldo = saldo - 100 WHERE id = 1;
UPDATE cuentas SET saldo = saldo + 100 WHERE id = 2;
COMMIT;
BEGIN TRANSACTION (o simplemente BEGIN) abre la transacción. Todas las operaciones que escribas después quedan en espera hasta que las confirmes con COMMIT o las deshagas con ROLLBACK.
COMMIT: confirmar los cambios
COMMIT guarda permanentemente todos los cambios realizados desde el BEGIN. Una vez ejecutado, no hay vuelta atrás.
BEGIN TRANSACTION;
INSERT INTO pedidos (cliente_id, total) VALUES (5, 59.99);
UPDATE clientes SET total_compras = total_compras + 59.99 WHERE id = 5;
COMMIT;
Si ambas operaciones se ejecutan sin error, COMMIT las graba definitivamente.
ROLLBACK: deshacer los cambios
ROLLBACK deshace todos los cambios realizados desde el BEGIN. La base de datos vuelve exactamente al estado anterior a la transacción.
BEGIN TRANSACTION;
DELETE FROM videogames WHERE developer = 'Valve';
-- ¡Ups! No queríamos borrar todos los juegos de Valve
ROLLBACK;
-- La tabla queda como estaba antes del DELETE
Esto es extremadamente útil como red de seguridad cuando ejecutas operaciones peligrosas.
Comportamiento por defecto: autocommit
Sin una transacción explícita, cada sentencia SQL se ejecuta en su propia transacción implícita que se confirma automáticamente. Esto se llama autocommit.
-- Esto se confirma automáticamente
DELETE FROM videogames WHERE id = 1;
-- El registro ya se borró permanentemente, no hay ROLLBACK posible
Cuando usas BEGIN, desactivas el autocommit hasta que ejecutes COMMIT o ROLLBACK.
Ejemplo clásico: transferencia bancaria
Este es el ejemplo más importante para entender por qué las transacciones existen:
BEGIN TRANSACTION;
-- Paso 1: Restar de la cuenta origen
UPDATE cuentas SET saldo = saldo - 500
WHERE id = 1 AND saldo >= 500;
-- Paso 2: Sumar a la cuenta destino
UPDATE cuentas SET saldo = saldo + 500
WHERE id = 2;
COMMIT;
Sin transacción, si el sistema falla entre el paso 1 y el paso 2, el dinero desaparece. Con transacción, si algo falla, ROLLBACK asegura que ninguno de los dos cambios se aplica.
Transacciones en SQLite
SQLite soporta transacciones completamente, con algunas particularidades:
- Puedes usar
BEGIN TRANSACTIONo simplementeBEGIN. - SQLite también acepta
ENDcomo sinónimo deCOMMIT. - SQLite usa bloqueo a nivel de archivo: solo una escritura a la vez (por eso no es ideal para alta concurrencia).
-- Las tres formas son equivalentes en SQLite:
BEGIN TRANSACTION;
BEGIN;
-- Y para confirmar:
COMMIT;
END;
Cuándo usar transacciones
Usa transacciones siempre que:
- Varias operaciones deben ser atómicas: transferencias, creación de entidades con relaciones, etc.
- Necesitas una red de seguridad: antes de ejecutar un
UPDATEoDELETEmasivo, envuélvelo en una transacción para poder hacerROLLBACKsi el resultado no es el esperado. - Rendimiento en inserciones masivas: envolver muchos
INSERTen una sola transacción es mucho más rápido que ejecutarlos individualmente, porque SQLite solo escribe al disco una vez en lugar de una vez por cadaINSERT.
-- Lento: cada INSERT es una transacción independiente
INSERT INTO logs VALUES (1, 'evento1');
INSERT INTO logs VALUES (2, 'evento2');
INSERT INTO logs VALUES (3, 'evento3');
-- ...miles más
-- Rápido: una sola transacción para todos
BEGIN TRANSACTION;
INSERT INTO logs VALUES (1, 'evento1');
INSERT INTO logs VALUES (2, 'evento2');
INSERT INTO logs VALUES (3, 'evento3');
-- ...miles más
COMMIT;
La diferencia de rendimiento puede ser de 100x o más en SQLite.
Nuestras tablas
Nombre de la Tabla: cuentas
| id | titular | saldo |
|---|---|---|
| 1 | Ana García | 1500 |
| 2 | Luis Pérez | 800 |
| 3 | Marta López | 2300 |
Nombre de la Tabla: movimientos
| id | cuenta_id | tipo | cantidad |
|---|---|---|---|
| 1 | 1 | ingreso | 1500 |
| 2 | 2 | ingreso | 800 |
| 3 | 3 | ingreso | 2300 |
Tablas de esta lección
Estructura
Datos de ejemplo (3 filas)
| id | titular | saldo |
|---|---|---|
| 1 | Ana García | 1500 |
| 2 | Luis Pérez | 800 |
| 3 | Marta López | 2300 |
Estructura
Datos de ejemplo (3 filas)
| id | cuenta_id | tipo | cantidad |
|---|---|---|---|
| 1 | 1 | ingreso | 1500 |
| 2 | 2 | ingreso | 800 |
| 3 | 3 | ingreso | 2300 |
Ejercicios
Realiza una transferencia de 200€ de Ana (id=1) a Luis (id=2). Usa una transacción: resta de Ana, suma a Luis, y registra ambos movimientos.
Inserta un nuevo cliente 'Carlos Ruiz' con saldo 0 y registra un ingreso de 1000€ a su cuenta, todo dentro de una transacción.
Ejecuta un BEGIN, borra todos los movimientos de tipo 'ingreso', y luego haz ROLLBACK para deshacer la operación. Verifica que los datos siguen intactos consultando la tabla movimientos.
Consulta el saldo de todas las cuentas junto con la suma total de sus movimientos. Usa un JOIN entre cuentas y movimientos agrupando por cuenta.