7. Gestión de Transacciones (TCL)
Introducción
Section titled “Introducción”El Lenguaje de Control de Transacciones (TCL - Transaction Control Language) es un componente fundamental de SQL que permite gestionar transacciones en bases de datos. Las transacciones garantizan la integridad de los datos al asegurar que las operaciones relacionadas se ejecuten como una unidad atómica, manteniendo la base de datos en un estado consistente incluso en caso de fallos.
7.1. Concepto de transacción
Section titled “7.1. Concepto de transacción”Una transacción es una secuencia de operaciones que se ejecutan como una única unidad lógica de trabajo. Las transacciones deben cumplir con las propiedades ACID:
- Atomicidad: Una transacción se ejecuta por completo o no se ejecuta en absoluto.
- Consistencia: Una transacción lleva la base de datos de un estado válido a otro estado válido.
- Aislamiento: Las transacciones se ejecutan de forma aislada, sin interferir entre sí.
- Durabilidad: Una vez confirmada una transacción, sus cambios persisten incluso ante fallos del sistema.
7.2. Iniciar transacciones (BEGIN, START TRANSACTION)
Section titled “7.2. Iniciar transacciones (BEGIN, START TRANSACTION)”Para iniciar una transacción explícitamente, se utilizan los comandos BEGIN o START TRANSACTION.
-- Iniciar una transacciónSTART TRANSACTION;-- oBEGIN;
-- Operaciones dentro de la transacciónUPDATE cuentas SET saldo = saldo - 1000 WHERE id_cuenta = 1;UPDATE cuentas SET saldo = saldo + 1000 WHERE id_cuenta = 2;-- En Oracle, las transacciones comienzan implícitamente con la primera instrucción DML-- No es necesario un comando explícito, pero se puede usar:SET TRANSACTION NAME 'transferencia_fondos';
-- Operaciones dentro de la transacciónUPDATE cuentas SET saldo = saldo - 1000 WHERE id_cuenta = 1;UPDATE cuentas SET saldo = saldo + 1000 WHERE id_cuenta = 2;Modos de transacción
Section titled “Modos de transacción”-- Iniciar transacción de solo lecturaSTART TRANSACTION READ ONLY;
-- Iniciar transacción con escrituraSTART TRANSACTION READ WRITE;
-- Iniciar transacción con un nivel de aislamiento específicoSTART TRANSACTION ISOLATION LEVEL SERIALIZABLE;-- Iniciar transacción de solo lecturaSET TRANSACTION READ ONLY;
-- Iniciar transacción con escritura (predeterminado)SET TRANSACTION READ WRITE;
-- Iniciar transacción con un nivel de aislamiento específicoSET TRANSACTION ISOLATION LEVEL SERIALIZABLE;7.3. Confirmar cambios (COMMIT)
Section titled “7.3. Confirmar cambios (COMMIT)”El comando COMMIT finaliza la transacción actual y hace permanentes todos los cambios realizados durante la transacción.
-- Iniciar transacciónSTART TRANSACTION;
-- OperacionesUPDATE productos SET stock = stock - 5 WHERE id_producto = 101;INSERT INTO ventas (id_producto, cantidad, fecha) VALUES (101, 5, NOW());
-- Confirmar cambiosCOMMIT;-- Las transacciones comienzan implícitamenteUPDATE productos SET stock = stock - 5 WHERE id_producto = 101;INSERT INTO ventas (id_producto, cantidad, fecha) VALUES (101, 5, SYSDATE);
-- Confirmar cambiosCOMMIT;7.4. Deshacer cambios (ROLLBACK)
Section titled “7.4. Deshacer cambios (ROLLBACK)”El comando ROLLBACK deshace todos los cambios realizados durante la transacción actual y finaliza la transacción.
-- Iniciar transacciónSTART TRANSACTION;
-- OperacionesUPDATE cuentas SET saldo = saldo - 5000 WHERE id_cuenta = 1;
-- Verificar saldo resultanteSELECT saldo FROM cuentas WHERE id_cuenta = 1;
-- Si el saldo es negativo, deshacer la transacciónROLLBACK;-- Las transacciones comienzan implícitamenteUPDATE cuentas SET saldo = saldo - 5000 WHERE id_cuenta = 1;
-- Verificar saldo resultanteSELECT saldo FROM cuentas WHERE id_cuenta = 1;
-- Si el saldo es negativo, deshacer la transacciónROLLBACK;Manejo de errores y ROLLBACK automático
Section titled “Manejo de errores y ROLLBACK automático”-- Establecer que los errores provoquen un rollback automáticoSET autocommit = 0;
START TRANSACTION;
-- Si esta operación falla, toda la transacción se revertiráUPDATE cuentas SET saldo = saldo - 1000 WHERE id_cuenta = 1;
-- Esta operación provocaría un error si la cuenta 999 no existeUPDATE cuentas SET saldo = saldo + 1000 WHERE id_cuenta = 999;
-- Si llegamos aquí sin errores, confirmamosCOMMIT;-- Manejo de errores con bloques PL/SQLDECLARE v_saldo_insuficiente EXCEPTION;BEGIN -- Verificar saldo UPDATE cuentas SET saldo = saldo - 1000 WHERE id_cuenta = 1;
-- Verificar si el saldo es negativo IF (SELECT saldo FROM cuentas WHERE id_cuenta = 1) < 0 THEN RAISE v_saldo_insuficiente; END IF;
-- Completar la transferencia UPDATE cuentas SET saldo = saldo + 1000 WHERE id_cuenta = 2;
-- Confirmar si todo está bien COMMIT;EXCEPTION WHEN v_saldo_insuficiente THEN DBMS_OUTPUT.PUT_LINE('Error: Saldo insuficiente'); ROLLBACK; WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM); ROLLBACK;END;/7.5. Puntos de guardado (SAVEPOINT, RELEASE SAVEPOINT)
Section titled “7.5. Puntos de guardado (SAVEPOINT, RELEASE SAVEPOINT)”Los puntos de guardado (savepoints) permiten dividir una transacción en partes más pequeñas, lo que posibilita revertir la transacción hasta un punto específico sin deshacer toda la transacción.
-- Iniciar transacciónSTART TRANSACTION;
-- Primera operaciónINSERT INTO pedidos (cliente_id, fecha) VALUES (101, NOW());SET @id_pedido = LAST_INSERT_ID();
-- Crear un punto de guardado después de insertar el pedidoSAVEPOINT pedido_creado;
-- Añadir productos al pedidoINSERT INTO detalles_pedido (pedido_id, producto_id, cantidad) VALUES (@id_pedido, 1, 2);INSERT INTO detalles_pedido (pedido_id, producto_id, cantidad) VALUES (@id_pedido, 2, 1);
-- Crear otro punto de guardadoSAVEPOINT productos_agregados;
-- Actualizar inventarioUPDATE productos SET stock = stock - 2 WHERE id = 1;
-- Si hay un problema con el inventario, volver al punto anterior-- ROLLBACK TO productos_agregados;
-- Si todo está bien, confirmarCOMMIT;-- Las transacciones comienzan implícitamenteINSERT INTO pedidos (cliente_id, fecha) VALUES (101, SYSDATE);
-- Obtener el ID del pedido insertadoDECLARE v_id_pedido pedidos.id%TYPE;BEGIN SELECT pedidos_seq.CURRVAL INTO v_id_pedido FROM DUAL;
-- Crear un punto de guardado después de insertar el pedido SAVEPOINT pedido_creado;
-- Añadir productos al pedido INSERT INTO detalles_pedido (pedido_id, producto_id, cantidad) VALUES (v_id_pedido, 1, 2); INSERT INTO detalles_pedido (pedido_id, producto_id, cantidad) VALUES (v_id_pedido, 2, 1);
-- Crear otro punto de guardado SAVEPOINT productos_agregados;
-- Actualizar inventario UPDATE productos SET stock = stock - 2 WHERE id = 1;
-- Si hay un problema con el inventario, volver al punto anterior -- ROLLBACK TO productos_agregados;
-- Eliminar un punto de guardado (ya no se puede volver a él) -- RELEASE SAVEPOINT pedido_creado;
-- Si todo está bien, confirmar COMMIT;END;/Eliminar puntos de guardado
Section titled “Eliminar puntos de guardado”-- Eliminar un punto de guardadoRELEASE SAVEPOINT pedido_creado;-- Eliminar un punto de guardadoRELEASE SAVEPOINT pedido_creado;7.6. Control de concurrencia y bloqueos
Section titled “7.6. Control de concurrencia y bloqueos”El control de concurrencia garantiza que múltiples transacciones puedan ejecutarse simultáneamente sin comprometer la integridad de los datos.
Niveles de aislamiento
Section titled “Niveles de aislamiento”Los niveles de aislamiento definen cómo las transacciones interactúan entre sí:
- READ UNCOMMITTED: Permite leer cambios no confirmados (dirty reads).
- READ COMMITTED: Solo permite leer cambios confirmados.
- REPEATABLE READ: Garantiza que las lecturas repetidas dentro de una transacción devuelvan los mismos resultados.
- SERIALIZABLE: El nivel más estricto, las transacciones se ejecutan como si fueran secuenciales.
-- Establecer nivel de aislamiento para la sesiónSET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- Establecer nivel de aislamiento para una transacción específicaSTART TRANSACTION ISOLATION LEVEL SERIALIZABLE;-- Establecer nivel de aislamiento para la sesiónALTER SESSION SET ISOLATION_LEVEL = SERIALIZABLE;
-- Establecer nivel de aislamiento para una transacción específicaSET TRANSACTION ISOLATION LEVEL READ COMMITTED;Bloqueos explícitos
Section titled “Bloqueos explícitos”-- Bloquear tablas para lecturaLOCK TABLES empleados READ;
-- Bloquear tablas para escrituraLOCK TABLES empleados WRITE;
-- Liberar todos los bloqueosUNLOCK TABLES;
-- Bloquear filas para actualizaciónSELECT * FROM empleados WHERE departamento_id = 10 FOR UPDATE;-- Bloquear filas para actualizaciónSELECT * FROM empleados WHERE departamento_id = 10 FOR UPDATE;
-- Bloquear filas para actualización sin esperar (falla si están bloqueadas)SELECT * FROM empleados WHERE departamento_id = 10 FOR UPDATE NOWAIT;
-- Bloquear filas con tiempo de esperaSELECT * FROM empleados WHERE departamento_id = 10 FOR UPDATE WAIT 5;Problemas comunes de concurrencia
Section titled “Problemas comunes de concurrencia”-
Lecturas sucias (Dirty Reads): Una transacción lee datos que otra transacción ha modificado pero aún no ha confirmado.
-
Lecturas no repetibles (Non-repeatable Reads): Una transacción lee el mismo registro dos veces y obtiene valores diferentes porque otra transacción modificó el registro entre las lecturas.
-
Lecturas fantasma (Phantom Reads): Una transacción ejecuta una consulta dos veces y la segunda vez aparecen registros adicionales porque otra transacción insertó nuevos registros que cumplen con los criterios de la consulta.
-
Bloqueos muertos (Deadlocks): Dos transacciones se bloquean mutuamente, cada una esperando recursos que la otra tiene bloqueados.
Comparación de niveles de aislamiento y problemas de concurrencia
Section titled “Comparación de niveles de aislamiento y problemas de concurrencia”| Nivel de aislamiento | Lecturas sucias | Lecturas no repetibles | Lecturas fantasma |
|---|---|---|---|
| READ UNCOMMITTED | Posible | Posible | Posible |
| READ COMMITTED | No | Posible | Posible |
| REPEATABLE READ | No | No | Posible (MySQL: No) |
| SERIALIZABLE | No | No | No |
Conclusión
Section titled “Conclusión”La gestión adecuada de transacciones es fundamental para mantener la integridad de los datos en sistemas de bases de datos. Las transacciones garantizan que las operaciones relacionadas se ejecuten como una unidad atómica, permitiendo deshacer cambios en caso de errores y asegurando que la base de datos permanezca en un estado consistente incluso en entornos multiusuario con acceso concurrente.