Aprende SQL · lección gratuita

Lección 42 · Transacciones: BEGIN, COMMIT, ROLLBACK y SAVEPOINT

Resumen

Una transacción agrupa varias operaciones para que se apliquen como una sola unidad atómica: o se confirman todas (COMMIT) o no se aplica ninguna (ROLLBACK). Esto garantiza consistencia ante errores y concurrencia, y es la base de las propiedades ACID (Atomicidad, Consistencia, Aislamiento, Durabilidad). Sin transacciones explícitas, SQLite envuelve cada sentencia en su propia transacción automática (autocommit).

Sintaxis / Conceptos

El flujo típico es BEGIN; ... sentencias ...; COMMIT;. Si algo sale mal antes del COMMIT, ejecutas ROLLBACK;. En SQLite, BEGIN admite modos (BEGIN DEFERRED por defecto, IMMEDIATE, EXCLUSIVE) que controlan cuándo se adquieren los bloqueos; para aprender basta con BEGIN.

Savepoints anidados: un SAVEPOINT es un "BEGIN dentro del BEGIN". Permite deshacer solo una porción del trabajo. ROLLBACK TO sp revierte hasta el savepoint pero mantiene activa la transacción y el propio savepoint (puedes seguir trabajando). RELEASE sp lo descarta integrando sus cambios en el nivel superior. Si haces COMMIT, se confirma todo lo que sobrevivió a los rollbacks parciales.

Errores comunes: olvidar el COMMIT deja la transacción abierta y bloqueada; hacer ROLLBACK sin BEGIN previo da error porque no hay transacción activa. No se puede anidar BEGIN dentro de BEGIN (para eso están los savepoints).

Nota de la lección: para no mutar la semilla, todos los ejemplos trabajan sobre tablas temporales (DROP TABLE IF EXISTS ...; CREATE TABLE ...), de modo que el script es idempotente y reproducible.
SELECT id, nombre, precio, stock FROM productos ORDER BY stock ASC LIMIT 6

Ejemplos

-- COMMIT: una transferencia atómica (descontar y abonar juntos)
DROP TABLE IF EXISTS cuentas_tmp;
CREATE TABLE cuentas_tmp (id INTEGER PRIMARY KEY, titular TEXT, saldo INTEGER);

BEGIN;
INSERT INTO cuentas_tmp VALUES (1,'Ana',1000), (2,'Beto',500);
UPDATE cuentas_tmp SET saldo = saldo - 200 WHERE id = 1;  -- Ana paga
UPDATE cuentas_tmp SET saldo = saldo + 200 WHERE id = 2;  -- Beto recibe
COMMIT;

SELECT id, titular, saldo FROM cuentas_tmp ORDER BY id;
-- ROLLBACK: deshacemos un cambio masivo y los datos vuelven a su estado original
DROP TABLE IF EXISTS inventario_tmp;
CREATE TABLE inventario_tmp AS SELECT id, nombre, stock FROM productos WHERE id <= 5;

BEGIN;
UPDATE inventario_tmp SET stock = 0;   -- ¡error! poner todo el stock en 0
ROLLBACK;                              -- lo deshacemos: nada se aplica

SELECT id, nombre, stock FROM inventario_tmp ORDER BY id;
-- SAVEPOINT: deshacer parcialmente sin abortar toda la transacción
DROP TABLE IF EXISTS log_tmp;
CREATE TABLE log_tmp (id INTEGER PRIMARY KEY, msg TEXT);

BEGIN;
INSERT INTO log_tmp VALUES (1,'inicio');
SAVEPOINT sp1;
INSERT INTO log_tmp VALUES (2,'temporal');   -- esto lo descartaremos
ROLLBACK TO sp1;                             -- deshace solo el id=2
INSERT INTO log_tmp VALUES (3,'final');
COMMIT;

SELECT id, msg FROM log_tmp ORDER BY id;     -- quedan 1 y 3, no el 2
💡 Las transacciones también mejoran el rendimiento en cargas masivas: envolver 10 000 INSERT en un solo BEGIN ... COMMIT es órdenes de magnitud más rápido que dejar que SQLite haga autocommit (un fsync a disco) tras cada fila.

Cheatsheet

SentenciaQué hace
BEGIN;Inicia una transacción (cambios provisionales)
COMMIT;Confirma todos los cambios de forma durable
ROLLBACK;Descarta todos los cambios de la transacción
SAVEPOINT s;Crea un punto de control intermedio
ROLLBACK TO s;Deshace hasta el savepoint s (sigue en transacción)
RELEASE s;Libera el savepoint s (integra sus cambios)

---

← Índices: CREATE INDEXOptimización (EXPLAIN QUERY PLAN) y motores de bases de datos →

Ver todas las lecciones de Aprende SQL →