Skip to content

7. TCL (Transaction Control Language)

El Lenguaje de Control de Transacciones (Transaction Control Language o TCL) es un subconjunto de SQL utilizado para gestionar los cambios realizados por las sentencias DML (Data Manipulation Language). TCL permite a los usuarios agrupar un conjunto de operaciones en unidades lógicas de trabajo llamadas transacciones, que pueden ser confirmadas o revertidas como una unidad.

Características principales de las transacciones

Section titled “Características principales de las transacciones”
  • 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 consistente a otro estado consistente
  • Aislamiento: Las transacciones se ejecutan de forma aislada unas de otras
  • Durabilidad: Una vez confirmada una transacción, sus cambios son permanentes

El comando COMMIT se utiliza para hacer permanentes los cambios realizados durante la transacción actual.

-- Sintaxis básica
COMMIT [WORK] [COMMENT 'texto_comentario'];
-- Ejemplo simple
INSERT INTO empleados (empleado_id, nombre, apellido) VALUES (101, 'Juan', 'Pérez');
UPDATE departamentos SET presupuesto = presupuesto + 10000 WHERE departamento_id = 20;
COMMIT; -- Confirma ambas operaciones
  1. Hace permanentes los cambios

    • Los cambios realizados por las sentencias DML se guardan permanentemente en la base de datos
    • Los cambios son visibles para otras sesiones
  2. Libera bloqueos

    • Se liberan todos los bloqueos adquiridos durante la transacción
    • Otros usuarios pueden acceder a los datos modificados
  3. Establece un punto de guardado

    • Se establece un punto de guardado implícito
    • Finaliza la transacción actual y comienza una nueva
  4. Libera recursos

    • Se liberan los recursos del sistema utilizados para la transacción
    • Se eliminan los datos de deshacer (undo) asociados a la transacción
-- COMMIT simple
INSERT INTO clientes (cliente_id, nombre) VALUES (1001, 'Empresa ABC');
COMMIT;
-- COMMIT con comentario (para auditoría)
UPDATE productos SET precio = precio * 1.05 WHERE categoria = 'Electrónica';
COMMIT COMMENT 'Incremento de precios 5% en electrónica';

Oracle realiza un COMMIT implícito en los siguientes casos:

  • Cuando se ejecuta un comando DDL (CREATE, ALTER, DROP, etc.)
  • Cuando se ejecuta un comando DCL (GRANT, REVOKE)
  • Cuando se cierra normalmente una sesión (EXIT o QUIT)
  • Cuando se ejecuta un comando SET AUTOCOMMIT ON

El comando ROLLBACK se utiliza para deshacer los cambios realizados durante la transacción actual que aún no han sido confirmados.

-- Sintaxis básica
ROLLBACK [WORK] [TO [SAVEPOINT] nombre_savepoint];
-- Ejemplo simple
INSERT INTO empleados (empleado_id, nombre, apellido) VALUES (102, 'María', 'Gómez');
UPDATE departamentos SET presupuesto = presupuesto - 5000 WHERE departamento_id = 30;
-- Si algo sale mal o se detecta un error
ROLLBACK; -- Revierte ambas operaciones
  1. Deshace los cambios

    • Revierte todos los cambios realizados por las sentencias DML desde el último COMMIT o desde el inicio de la transacción
    • Los datos vuelven a su estado anterior
  2. Libera bloqueos

    • Se liberan todos los bloqueos adquiridos durante la transacción
    • Otros usuarios pueden acceder a los datos
  3. Elimina savepoints

    • Se eliminan todos los savepoints establecidos durante la transacción
  4. Finaliza la transacción

    • Termina la transacción actual y comienza una nueva

Utilizando savepoints, es posible realizar un ROLLBACK parcial, deshaciendo solo una parte de la transacción.

-- Iniciar transacción
INSERT INTO clientes (cliente_id, nombre) VALUES (1002, 'Empresa XYZ');
-- Establecer un savepoint
SAVEPOINT despues_cliente;
-- Continuar la transacción
INSERT INTO pedidos (pedido_id, cliente_id, total) VALUES (5001, 1002, 1500);
INSERT INTO pedidos (pedido_id, cliente_id, total) VALUES (5002, 1002, 2500);
-- Si hay un problema con los pedidos
ROLLBACK TO SAVEPOINT despues_cliente; -- Deshace solo las inserciones de pedidos
-- Continuar con la transacción
INSERT INTO pedidos (pedido_id, cliente_id, total) VALUES (5003, 1002, 3000);
-- Confirmar toda la transacción
COMMIT;

Oracle realiza un ROLLBACK implícito en los siguientes casos:

  • Cuando se produce un fallo del sistema
  • Cuando se cierra anormalmente una sesión (p. ej., por un error de red)
  • Cuando se produce un error grave durante la ejecución de una sentencia

SAVEPOINT - Puntos de guardado intermedios

Section titled “SAVEPOINT - Puntos de guardado intermedios”

El comando SAVEPOINT establece un punto de guardado dentro de la transacción actual, permitiendo deshacer parte de una transacción sin tener que deshacer toda la transacción.

-- Sintaxis básica
SAVEPOINT nombre_savepoint;
-- Ejemplo simple
INSERT INTO empleados (empleado_id, nombre) VALUES (103, 'Carlos');
SAVEPOINT sp_despues_empleado;
INSERT INTO departamentos (departamento_id, nombre) VALUES (50, 'Innovación');
-- Si hay un problema con la inserción del departamento
ROLLBACK TO SAVEPOINT sp_despues_empleado;
-- Continuar con la transacción
INSERT INTO departamentos (departamento_id, nombre) VALUES (51, 'Investigación');
COMMIT;
  • Se pueden crear múltiples savepoints dentro de una transacción
  • Los savepoints permiten un control más granular de las transacciones
  • Si se crea un savepoint con el mismo nombre que uno existente, el nuevo savepoint reemplaza al anterior
  • Los savepoints se eliminan automáticamente cuando se ejecuta un COMMIT o un ROLLBACK completo
-- Iniciar transacción
DELETE FROM empleados WHERE departamento_id = 10;
SAVEPOINT sp_despues_eliminar_dept10;
UPDATE empleados SET salario = salario * 1.1 WHERE departamento_id = 20;
SAVEPOINT sp_despues_actualizar_dept20;
INSERT INTO historial_cambios (descripcion) VALUES ('Actualización de salarios dept 20');
SAVEPOINT sp_despues_historial;
-- Si hay un problema con la inserción en el historial
ROLLBACK TO SAVEPOINT sp_despues_actualizar_dept20;
-- Si hay un problema con la actualización de salarios
ROLLBACK TO SAVEPOINT sp_despues_eliminar_dept10;
-- Si todo está bien
COMMIT;

Oracle Database Express Edition (XE) es una versión gratuita de Oracle Database con algunas limitaciones, pero el manejo de transacciones funciona igual que en las versiones estándar.

-- Verificar el modo de transacción actual
SHOW AUTOCOMMIT;
-- Activar el modo autocommit (cada sentencia es una transacción)
SET AUTOCOMMIT ON;
-- Desactivar el modo autocommit (modo manual, recomendado)
SET AUTOCOMMIT OFF;
-- Ver transacciones activas
SELECT xid, status, start_time, log_io, phy_io
FROM v$transaction;
-- Ver sesiones con transacciones pendientes
SELECT s.sid, s.serial#, s.username, s.status, t.used_ublk, t.start_time
FROM v$session s, v$transaction t
WHERE s.saddr = t.ses_addr;
-- Ver bloqueos de transacciones
SELECT l.session_id, s.username, l.lock_type, l.mode_held, l.mode_requested
FROM v$lock l, v$session s
WHERE l.session_id = s.sid
AND l.lock_type = 'TX';

Oracle XE tiene algunas limitaciones que pueden afectar a las transacciones:

  • Límite de uso de memoria (2GB)
  • Límite de almacenamiento (12GB en Oracle XE 18c)
  • Límite de uso de CPU (hasta 2 cores)

Estas limitaciones pueden afectar al rendimiento de las transacciones grandes, pero no a su funcionalidad básica.

Oracle soporta diferentes niveles de aislamiento que determinan cómo interaccionan las transacciones concurrentes.

-- Establecer el nivel de aislamiento para la sesión actual
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- Establecer el nivel de aislamiento para una transacción específica
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
NivelDescripciónProblemas que previene
READ COMMITTEDNivel predeterminado. Solo ve datos confirmados por otras transaccionesLecturas sucias
SERIALIZABLEMayor nivel de aislamiento. Ve un snapshot de los datos al inicio de la transacciónLecturas sucias, lecturas no repetibles, lecturas fantasma
READ ONLYSimilar a SERIALIZABLE, pero no permite modificacionesLecturas sucias, lecturas no repetibles, lecturas fantasma

Las transacciones distribuidas involucran múltiples bases de datos y utilizan el protocolo de commit en dos fases (2PC) para garantizar la consistencia.

Configuración de transacciones distribuidas

Section titled “Configuración de transacciones distribuidas”
-- Crear un enlace de base de datos (database link)
CREATE DATABASE LINK remote_db
CONNECT TO usuario IDENTIFIED BY contraseña
USING 'conexion_tns';
-- Iniciar una transacción distribuida
INSERT INTO empleados VALUES (104, 'Ana', 'Martínez');
INSERT INTO empleados@remote_db VALUES (104, 'Ana', 'Martínez');
-- Confirmar la transacción distribuida
COMMIT;

Gestión de errores en transacciones distribuidas

Section titled “Gestión de errores en transacciones distribuidas”
-- Consultar transacciones distribuidas en duda
SELECT * FROM dba_2pc_pending;
-- Resolver manualmente una transacción en duda
COMMIT FORCE 'transaction_id';
-- o
ROLLBACK FORCE 'transaction_id';
  1. Mantener transacciones cortas

    • Las transacciones largas consumen más recursos y pueden causar bloqueos prolongados
    • Divida las operaciones grandes en transacciones más pequeñas cuando sea posible
  2. Confirmar o revertir explícitamente

    • Siempre termine las transacciones con un COMMIT o ROLLBACK explícito
    • Evite depender de los COMMIT o ROLLBACK implícitos
  3. Usar savepoints estratégicamente

    • Establezca savepoints antes de operaciones complejas o potencialmente problemáticas
    • Use nombres descriptivos para los savepoints
  4. Gestionar bloqueos adecuadamente

    • Sea consciente de los bloqueos que generan sus transacciones
    • Considere usar SELECT FOR UPDATE cuando sea necesario bloquear filas específicas
  5. Manejar excepciones

    • Implemente manejo de excepciones adecuado en bloques PL/SQL
    • Realice ROLLBACK en caso de errores inesperados

Ejemplo de transacción bien estructurada en PL/SQL

Section titled “Ejemplo de transacción bien estructurada en PL/SQL”
DECLARE
v_error EXCEPTION;
v_count NUMBER;
BEGIN
-- Iniciar transacción (implícito en PL/SQL)
-- Verificar condiciones previas
SELECT COUNT(*) INTO v_count FROM clientes WHERE cliente_id = 1001;
IF v_count = 0 THEN
RAISE v_error;
END IF;
-- Establecer savepoint
SAVEPOINT sp_inicio;
-- Realizar operaciones
INSERT INTO pedidos (pedido_id, cliente_id, total) VALUES (6001, 1001, 5000);
-- Establecer otro savepoint
SAVEPOINT sp_despues_pedido;
-- Actualizar inventario
UPDATE inventario SET cantidad = cantidad - 10 WHERE producto_id = 101;
IF SQL%ROWCOUNT = 0 THEN
ROLLBACK TO SAVEPOINT sp_despues_pedido;
RAISE v_error;
END IF;
-- Confirmar si todo está bien
COMMIT;
DBMS_OUTPUT.PUT_LINE('Transacción completada con éxito');
EXCEPTION
WHEN v_error THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('Error en la transacción. Cambios revertidos.');
WHEN OTHERS THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('Error inesperado: ' || SQLERRM);
RAISE;
END;
/
🐝