CodeGym /Cursos /SQL SELF /Ejemplo de uso de transacciones en escenarios reales

Ejemplo de uso de transacciones en escenarios reales

SQL SELF
Nivel 39 , Lección 3
Disponible

A veces las transacciones se parecen a personajes de pelis de superhéroes. Salvan nuestras bases de datos de desastres cuando hay fallos, errores o problemas. Si tienes una tarea que necesita ejecutar varias operaciones que no se pueden separar, las transacciones aseguran que todo se haga como un solo bloque. Vamos a ver cómo funciona esto con el ejemplo de procesar pagos.

Procesamiento de pagos

Imagina la situación clásica: tienes dos cuentas bancarias y queremos transferir dinero de una a otra. No es solo una operación de "un botón". Hay que asegurarse de que quitamos bien el dinero de una cuenta y lo sumamos a la otra. Cualquier error puede ser catastrófico: o las dos cuentas se quedan igual, o el balance se rompe (por ejemplo, el dinero desaparece o aparece "de la nada").

Escenario: Transferencia de dinero entre cuentas

Aquí tienes nuestro código. Léelo con atención, como si fuera un mensaje de una galaxia lejana:

-- Empezamos la transacción
BEGIN;

-- Paso 1. Quitamos dinero de la cuenta del remitente
UPDATE accounts
SET balance = balance - 100
WHERE account_id = 1;

-- Paso 2. Añadimos dinero a la cuenta del destinatario
UPDATE accounts
SET balance = balance + 100
WHERE account_id = 2;

-- ¿Todo ha ido bien? ¡Entonces guardamos los cambios!
COMMIT;

¿Qué es lo importante aquí?

  • Si en el Paso 1 o Paso 2 algo sale mal (por ejemplo, error en la consulta, falta de fondos), la transacción puede ser revertida con ROLLBACK, y los datos se quedan como estaban.
  • COMMIT garantiza que los cambios solo se aplican si TODOS los pasos salen bien.

Añadiendo comprobación de saldo

¿Y si el remitente no tiene suficiente dinero para la transferencia? Vamos a añadir una comprobación de saldo para no dejarlo "en números rojos" sin querer.

-- Empezamos la transacción
BEGIN;

-- Obtenemos el saldo actual del remitente
DO $$
DECLARE
    current_balance NUMERIC;
BEGIN
    SELECT balance INTO current_balance FROM accounts WHERE account_id = 1;

    -- Comprobamos si hay suficiente dinero
    IF current_balance >= 100 THEN
        -- Si hay suficiente, hacemos la transferencia
        UPDATE accounts
        SET balance = balance - 100
        WHERE account_id = 1;

        UPDATE accounts
        SET balance = balance + 100
        WHERE account_id = 2;

        -- Guardamos los cambios
        COMMIT;
    ELSE
        -- Si no hay suficiente, revertimos
        ROLLBACK;
        RAISE NOTICE '¡Fondos insuficientes para la transferencia!';
    END IF;
END $$;

¿Qué tiene de interesante esto?

  • Usamos un bloque PL/pgSQL con comprobación de condición usando IF. Si el saldo es menor que la cantidad necesaria, la transacción se rechaza y no cambia nada.
  • ROLLBACK cancela los cambios si se han empezado (aunque aquí todavía no hay nada que cancelar, pero es buena práctica).
¡Importante!

Esta lección está dedicada a escenarios reales de uso de transacciones, así que he puesto aquí un ejemplo de la vida real. Lleva un procedimiento almacenado y está escrito usando PL-SQL. Creo que ya tienes suficiente experiencia para entender cómo funciona todo esto. Más adelante volveremos al tema de PL-SQL y veremos ejemplos mucho más complejos.

Actualización masiva de datos en una transacción

Crear una transacción no solo sirve para transferencias de dinero. Por ejemplo, tenemos una base de datos de una tienda online donde cada día decenas de pedidos pueden cambiar de estado, por ejemplo, de "en entrega" a "completado". ¿Cómo actualizar muchas filas de golpe y, si hay un fallo, poder revertir los cambios? Pues usando una transacción, claro.

Veamos otro escenario: actualización de estados de pedidos.

Aquí tienes un ejemplo:

-- Empezamos la transacción
BEGIN;

-- Paso 1. Actualizamos pedidos cuya fecha de entrega ya pasó
UPDATE orders
SET status = 'completado'
WHERE delivery_date < CURRENT_DATE;

-- Paso 2. Avisamos de que la actualización fue bien
RAISE NOTICE 'Todos los estados de los pedidos se han actualizado correctamente.';

-- Aplicamos los cambios
COMMIT;

¿Y si algo sale mal?

Siempre puede haber un error. Por ejemplo, te olvidas de poner la condición WHERE y ahora todos los pedidos han cambiado su estado a completado. Para evitar estas situaciones, es importante terminar la transacción o revertirla explícitamente.

Veamos el escenario de revertir:

-- Empezamos la transacción
BEGIN;

-- Paso 1. Intento de actualizar pedidos sin condición (¡ups, error!)
UPDATE orders
SET status = 'completado';

-- Revertimos la transacción por el error
ROLLBACK;

-- Ahora los pedidos siguen igual

Añadiendo un poco de "flexibilidad" con SAVEPOINT

No siempre hay que revertir toda la transacción. Si tu escenario tiene varios pasos, puede que solo quieras revertir uno. Aquí es donde SAVEPOINT te salva la vida.

Ahora nuestro escenario es: procesar varios pasos con la opción de revertir solo uno de ellos.

Imagina que procesas un pedido con varios pasos: quitar productos del almacén, actualizar el estado del pedido, enviar notificación al cliente. Si la notificación falla, quieres revertir solo ese paso, pero guardar los cambios en la base.

-- Empezar la transacción
BEGIN;

-- Paso 1. Quitamos productos del almacén
UPDATE products
SET stock = stock - 1
WHERE product_id = 101;

-- Guardamos punto de reversión
SAVEPOINT step1;

-- Paso 2. Actualizamos el estado del pedido
UPDATE orders
SET status = 'enviado'
WHERE order_id = 202;

-- Intento de enviar notificación al cliente
SAVEPOINT step2;
-- ¡Uy, error en el proceso de notificación!
ROLLBACK TO SAVEPOINT step2;

-- Decidimos que es seguro terminar la transacción
COMMIT;

Conclusión

Las transacciones no son solo una herramienta técnica, son la garantía de la integridad de tus datos. Te protegen del "efecto dominó", cuando un error puede romper todo el sistema. Cada vez que hagas varias operaciones relacionadas, pregúntate: "¿Y si una de ellas falla?" Si la respuesta es "sería un desastre", entonces toca usar una transacción. Recuerda: mejor gastar unos minutos escribiendo una transacción que horas recuperando datos después de un fallo. ¡Tus usuarios (y tus nervios) te lo agradecerán!

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION