Transacción
Una transacción es una secuencia de operaciones que se ejecutan como una unidad lógica.
Una unidad lógica significa que todas las operaciones deben completarse con éxito o ninguna de ellas debe aplicarse. Esto es crucial para mantener la integridad de los datos en situaciones donde múltiples usuarios pueden estar accediendo y modificando la base de datos al mismo tiempo.
Debes tener en cuenta que las transacciones NO conocen tu lógica de negocio. NO te protegen por ejemplo de que tu script intente enviar dinero de una cuenta a otra que no existe.
La transacción evita que se realicen cambios parciales en caso de ocurrir una excepción, por ejemplo, si el servidor se cae o si la conexión se pierde durante la ejecución de una operación. NUNCA de problemas derivados de la lógica de tu aplicación.
Propiedades ACID
Las transacciones en los SGBD deben cumplir con las propiedades ACID (Atomicity, Consistency, Isolation, Durability):
- Atomicidad: Garantiza que todas las operaciones de la transacción se completen con éxito o ninguna de ellas se aplique. Si una operación falla, se revierte toda la transacción.
- Consistencia: Asegura que la base de datos pase de un estado válido a otro estado válido. Todas las reglas de integridad deben cumplirse.
- Aislamiento: Permite que las transacciones se ejecuten de manera independiente y aislada, evitando que los cambios de una transacción sean visibles para otras hasta que se complete.
- Durabilidad: Una vez que una transacción se ha confirmado, sus cambios son permanentes, incluso en caso de fallos del sistema.
Atomicidad
Es la propiedad que asegura que todas las operaciones de una transacción se ejecuten completamente o no se ejecuten en absoluto. Si alguna operación falla, todas las operaciones anteriores se deshacen, garantizando que la base de datos no quede en un estado intermedio inconsistente.
Consistencia
Es la propiedad que asegura que una transacción lleva a la base de datos de un estado válido a otro estado válido. Esto significa que todas las reglas de integridad, como claves primarias, foráneas y restricciones, deben cumplirse antes y después de la transacción.
Aislamiento
Es la propiedad que garantiza que las transacciones se ejecuten de manera independiente. Esto significa que los cambios realizados por una transacción no son visibles para otras transacciones hasta que se completa la transacción. Esto evita problemas como lecturas sucias, lecturas no repetibles y fantasmas.
Durabilidad
Es la propiedad que asegura que una vez que una transacción se ha confirmado, sus cambios son permanentes, incluso en caso de fallos del sistema.
Esto se logra mediante el uso de registros de transacciones y copias de seguridad, que permiten recuperar el estado de la base de datos en caso de un fallo.
Sintaxis
Para trabajar con transacciones en MySQL, se utilizan los siguientes comandos:
START TRANSACTION; -- Inicia una nueva transacción
-- Cuerpo de la transacción
COMMIT; -- Confirma la transacción, aplicando todos los cambios
ROLLBACK; -- Deshace la transacción, revertiendo todos los cambios
En SQLite, sustituye START por BEGIN.
Ejemplo
Vamos a partir de una tabla como esta:
DROP TABLE IF EXISTS cuentas;
CREATE TABLE cuentas (
id INTEGER PRIMARY KEY,
nombre TEXT NOT NULL,
saldo INTEGER NOT NULL DEFAULT 0
);
INSERT INTO cuentas (id, nombre, saldo) VALUES
(1, 'Cuenta A', 1000),
(2, 'Cuenta B', 500);
Supongamos que queremos transferir 100 unidades de saldo de la Cuenta A a la Cuenta B. Esto implica dos operaciones: restar 100 de la Cuenta A y sumar 100 a la Cuenta B.
Podriamos hacerlo así en MySQL:
START TRANSACTION;
UPDATE cuentas SET saldo = saldo - 100 WHERE id = 1;
UPDATE cuentas SET saldo = saldo + 100 WHERE id = 2;
COMMIT;
La transferencia se realizaría sin problemas. ¿Que pasa si provocamos un error en el propio motor de MySQL?
START TRANSACTION;
UPDATE cuentas SET saldo = saldo - 100 WHERE id = 1;
UPDATE cuentas SET saldos = saldo + 100 WHERE id = 2; -- ID que no existe: no lanza error
COMMIT;
En este caso, la segunda operación fallaría porque la columna saldos no existe. Sin embargo, como no hemos ejecutado el COMMIT, MySQL revertirá automáticamente todos los cambios realizados en la transacción.
Ten en cuenta que esto no es lo mismo que si el error se produce en tu código, por ejemplo, si intentas transferir dinero a una cuenta que no existe:
START TRANSACTION;
UPDATE cuentas SET saldo = saldo - 100 WHERE id = 1;
UPDATE cuentas SET saldo = saldo + 100 WHERE id = 999;
COMMIT;
En este caso, la segunda operación fallaría porque la cuenta con id = 999 no existe. Sin embargo, la transacción se completaría y harías desaparecer 100 unidades de la Cuenta A, dejando la base de datos en un estado inconsistente.