Aprende SQL · lección gratuita
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).
BEGIN: inicia una transacción; a partir de aquí los cambios son provisionales y no visibles para otras conexiones hasta confirmar.COMMIT: confirma de forma permanente y durable todos los cambios desde el BEGIN.ROLLBACK: descarta todos los cambios desde el BEGIN, dejando los datos como estaban antes.SAVEPOINT nombre: crea un punto de control intermedio dentro de la transacción; permite deshacer parcialmente con ROLLBACK TO nombre sin abortar toda la transacción.RELEASE nombre: libera (confirma dentro de la transacción) un savepoint, ya no se podrá volver a él.ROLLBACK evita estados inconsistentes (el clásico ejemplo de transferencia bancaria: descontar de una cuenta y abonar en otra deben ocurrir juntas o ninguna).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
-- 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 000INSERTen un soloBEGIN ... COMMITes órdenes de magnitud más rápido que dejar que SQLite haga autocommit (un fsync a disco) tras cada fila.
| Sentencia | Qué 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 →