Saltearse al contenido

Transacciones

Una Transacción es un agrupamiento de una o más sentencias SQL que realizan algún cambio sobre una base de datos, como una unidad lógica de ejecución.

El objetivo de una Transacción es mantener la integridad de los datos al realizar una o más operaciones que modifican a estos, aún si hay fallas en la ejecución, si otras Transacciones se ejecutan concurrentemente o si ocurre un siniestro (por ejemplo, un corte de energía).

Una Transacción solo se ejecutará exitosamente si cada una de las sentencias que la componen se ejecutan exitosamente. De lo contrario, si alguna de ellas falla, la Transacción entera debe fallar, descartando los cambios que se hayan realizado.

Usualmente, se dice que una Transacción debe poseer las características descritas por el acrónimo del inglés, ACID, el cual viene de Atomic (atómica), Consistent (consistente), Isolated (aislada) and Durable (durable).

Vamos a explicar estas características a continuación:

  • Atómica: una Transacción debe ser ejecutada como una unidad lógica de trabajo, y todas sus modificaciones deben ser completadas, de lo contrario debe restituir los cambios que haya hecho hasta volver al estado previo a su ejecución.
  • Consistente: al finalizar su ejecución, la integridad y consistencia de los datos se debe mantener.
  • Aislada: una Transacción debe realizar cambios independientemente los cambios que realicen otras Transacciones.
  • Durable: una vez que una Transacción se ejecuta con éxito, los cambios realizados se deben mantener permanentemente.

Ejemplo de uso

Veamos un ejemplo clásico del uso de Transacciones.

Vamos a especificar los pasos que se deben seguir para realizar una transferencia de fondos entre dos cajas de ahorro en una base de datos de un banco. En este ejemplo, dos clientes del mismo banco quieren transferir dinero entre sí.

Un DER (extremadamente) simplificado de esta base de datos puede ser el siguiente:

Digamos que existen las tablas clientes, cuentas y transferencias, y el cliente Cristian Martínez quiere transferir, desde su caja de ahorro con id de cuenta 1246542576, $5000 a la caja de ahorro, con id de cuenta 1945387487, del cliente Miguel Rodríguez. Entonces las sentencias SQL que deberíamos ejecutar son las siguientes:

  1. Restar $5000 de la cuenta origen.
1
UPDATE cuentas
2
SET saldo = saldo - 5000
3
WHERE id_cuenta = 1246542576;
  1. Sumar $5000 a la cuenta destino.
1
UPDATE cuentas
2
SET saldo = saldo + 5000
3
WHERE id_cuenta = 1945387487;
  1. Registrar el movimiento en la tabla transferencias.
1
INSERT INTO transferencias (id_cuenta_origen, id_cuenta_destino, monto, fecha)
2
VALUES (1246542576, 1945387487, 5000, CURDATE());

Como vemos, cada paso de la transferencia es importante e indispensable para que no haya inconsistencias en los datos. Es decir, para que la transferencia de fondos sea considerada exitosa, todas las sentencias deben ejecutarse con éxito.

Si no se usarán Transacciones para realizar estos cambios y ocurre algún fallo, un cliente puede quedar con saldo de más o de menos. Se puede perder o generar dinero en la base de datos y los registros no coincidirían con los saldos.

Al usar una Transacción para realizar todos los pasos como uno solo, nos aseguramos que, todas las sentencias se ejecuten con éxito o, si alguna falla, se vuelva al estado previo a la Transacción. Manteniendo la integridad de los datos.

Sintaxis

La forma de usar Transacciones explícitas, es rodear las sentencias críticas con un inicio y fin de la Transacción. Para esto, en SQL existe una sintaxis específica, que, dependiendo del SGBD, puede variar en la práctica.

Para marcar el inicio de una Transacción se debe ejecutar la sentencia START TRANSACTION, esta sentencia es parte del estándar SQL y está soportada por MySQL. Algunos otros SGBD utilizan la sentencia BEGIN TRANSACTION (SQL Server) o BEGIN (PostgreSQL).

A continuación, se deben escribir las sentencias que queremos incluir en la Transacción, y finalizamos con la sentencia COMMIT, la cual marca el fin de una Transacción exitosa y le dice al SGBD que se deben guardar permanentemente los cambios realizados.

Si alguna sentencia falla antes de que se ejecute un COMMIT, se volverá automáticamente al estado previo al inicio de la Transacción, mediante un proceso conocido como rollback (retroceso). Este proceso descarta todos los cambios que se hayan hecho desde el punto en que se inició la Transacción.

El proceso de rollback es automático en caso de un fallo en la ejecución, pero para situaciones en las que debamos ejecutar un rollback de manera manual, existe la sentencia ROLLBACK. Esta sentencia también marca explícitamente el fin de una Transacción descartando los cambios realizados, como mencionamos.

El uso manual de ROLLBACK usualmente implica la ejecución de código SQL programáticamente (usando sentencias de control de flujo). Es decir, controlar si una condición se cumple o no, y, en consecuencia, ejecutar o no el ROLLBACK. Veremos su uso más adelante.

Veamos cómo quedaría el ejemplo anterior aplicando una Transacción explícita.

1
START TRANSACTION;
2
3
UPDATE cuentas
4
SET saldo = saldo - 5000
5
WHERE id_cuenta = 1246542576;
6
7
UPDATE cuentas
8
SET saldo = saldo + 5000
9
WHERE id_cuenta = 1945387487;
10
11
INSERT INTO transferencias (id_cuenta_origen, id_cuenta_destino, monto, fecha)
12
VALUES (1246542576, 1945387487, 5000, NOW());
13
14
COMMIT;

En este ejemplo, luego de ejecutar START TRANSACTION, MySQL va agrupando todas las sentencias siguientes como una sola unidad de ejecución, y se mantiene a la espera de una sentencia COMMIT (o ROLLBACK) para completar la Transacción.

Cuando se ejecuta el COMMIT se guardan los cambios permanentemente en la base de datos.

Bibliografía

  1. https://dev.mysql.com/doc/refman/8.0/en/commit.html