Handlers · SIGNAL · SQLSTATE · Transacciones
UTN Mar del Plata
TUP --- 2do Año | Plan 2024
Trabajo Práctico Integrador
Ejercicios conceptuales y prácticos sobre manejo de errores y transacciones
Objetivo: Analizar el comportamiento de handlers en MySQL, predecir el flujo de ejecución (ejercicios conceptuales) y aplicar los conceptos en la escritura de procedimientos almacenados con manejo de errores, transacciones, SIGNAL y validaciones de negocio (ejercicios prácticos).
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT 'Handler general';
END;
BEGIN
SIGNAL SQLSTATE '45000';
END;
SELECT 'Sigo en el procedimiento';
END;
BEGIN
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT 'Handler interno';
END;
SIGNAL SQLSTATE '45000';
SELECT 'Dentro del bloque';
END;
SELECT 'Fuera del bloque';
END;
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT 'Handler externo';
END;
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT 'Handler interno';
RESIGNAL;
END;
SIGNAL SQLSTATE '45000';
END;
SELECT 'Fin del procedimiento';
END;
BEGIN
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
SELECT 'Handler CONTINUE';
END;
SIGNAL SQLSTATE '45000';
SELECT 'Sigo dentro del bloque';
END;
SELECT 'Fin del procedimiento';
END;
-- hijo
CREATE PROCEDURE hijo()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT 'Error en hijo';
END;
SIGNAL SQLSTATE '45000';
END;
-- padre
CREATE PROCEDURE padre()
BEGIN
CALL hijo();
SELECT 'Padre sigue';
END;
padre()?BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT 'Handler externo';
END;
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
SELECT 'Handler interno CONTINUE';
END;
SIGNAL SQLSTATE '45000';
SELECT 'Dentro del bloque';
END;
SELECT 'Fin del procedimiento';
END;
BEGIN
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT 'Handler interno';
END;
SIGNAL SQLSTATE '45000';
END;
SIGNAL SQLSTATE '45000';
SELECT 'Fin';
END;
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
SELECT 'Handler externo CONTINUE';
END;
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT 'Handler interno EXIT';
END;
SIGNAL SQLSTATE '45000';
END;
SELECT 'Después del bloque';
SIGNAL SQLSTATE '45000';
SELECT 'Fin del procedimiento';
END;
-- hijo
CREATE PROCEDURE hijo()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT 'Handler hijo';
RESIGNAL;
END;
SIGNAL SQLSTATE '45000';
END;
-- padre
CREATE PROCEDURE padre()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT 'Handler padre';
END;
CALL hijo();
SELECT 'Padre sigue';
END;
padre()?BEGIN
START TRANSACTION;
INSERT INTO logs (mensaje) VALUES ('Inicio de proceso');
SAVEPOINT antes_operacion;
INSERT INTO operaciones (detalle) VALUES ('Operación crítica');
-- Supongamos que aquí se evalúa una condición de negocio (por ejemplo,
-- validación de stock, saldo, etc.) y se asigna el valor de @error_detectado
-- en función de si la operación es válida o no.
IF @error_detectado = 1 THEN
ROLLBACK TO SAVEPOINT antes_operacion; -- Se deshace solo la inserción en operaciones
SELECT 'Operación cancelada, log preservado' AS resultado;
ELSE
COMMIT; -- Confirma todo (log y operación)
SELECT 'Todo confirmado' AS resultado;
END IF;
END;
@error_detectado representa un flag de error de lógica de negocio que se supone cargada previamente (por ejemplo, después de verificar stock, saldo, etc.).@error_detectado = 1, ¿qué operaciones se confirman al final?BEGIN
START TRANSACTION;
UPDATE cuentas SET saldo = saldo - 100 WHERE id = 1;
UPDATE cuentas SET saldo = saldo + 100 WHERE id = 2;
-- Validación de negocio sin handler
IF (SELECT saldo FROM cuentas WHERE id = 1) < 0 THEN
ROLLBACK;
SELECT 'Transferencia cancelada por saldo negativo';
ELSE
COMMIT;
SELECT 'Transferencia exitosa';
END IF;
END;
BEGIN
-- Transacción 1
START TRANSACTION;
INSERT INTO auditoria (evento) VALUES ('Inicio proceso');
COMMIT;
-- Transacción 2
START TRANSACTION;
UPDATE datos SET valor = valor * 2;
-- Si algo falla aquí, solo afecta a esta transacción
IF (SELECT COUNT(*) FROM datos) = 0 THEN
ROLLBACK;
ELSE
COMMIT;
END IF;
-- Transacción 3
START TRANSACTION;
INSERT INTO logs (mensaje) VALUES ('Proceso finalizado');
COMMIT;
END;
BEGIN
DECLARE v_id INT;
DECLARE EXIT HANDLER FOR NOT FOUND
BEGIN
SELECT 'Socio no encontrado' AS aviso;
END;
SELECT id_socio INTO v_id FROM socios WHERE id_socio = 999;
SELECT 'Socio existe' AS resultado;
END;
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SELECT 'Error: transacción revertida' AS resultado;
END;
START TRANSACTION;
INSERT INTO tabla1 (col) VALUES ('valor1');
-- @condicion es un flag que se supone cargado previamente según alguna
-- condición de negocio (por ejemplo, validación de datos)
IF @condicion = 1 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Error lógico';
END IF;
INSERT INTO tabla2 (col) VALUES ('valor2');
COMMIT;
END;
@condicion representa una validación de negocio (ej. stock insuficiente, saldo negativo, etc.) que puede activar el error.@condicion = 1, ¿qué se imprime y qué ocurre con los datos?@condicion = 0, ¿qué se imprime?En los siguientes ejercicios deberá escribir el código SQL del procedimiento almacenado según las especificaciones dadas. Utilice manejo de errores con handlers, transacciones, SIGNAL y validaciones según corresponda.
Cree un procedimiento almacenado llamado eliminarPlanSeguro que reciba como parámetro p_id_plan INT e intente eliminar el plan de la tabla planes.
SQLEXCEPTION.-- Escriba aquí el procedimiento solicitado: DELIMITER $$ CREATE PROCEDURE eliminarPlanSeguro(IN p_id_plan INT) BEGIN END$$ DELIMITER ;
Cree un procedimiento almacenado llamado ultimaFechaActividadSocio que reciba p_id_socio INT y muestre la fecha más alta de actividad de ese socio.
SIGNAL mostrando un mensaje de error.-- Escriba aquí el procedimiento: DELIMITER $$ CREATE PROCEDURE ultimaFechaActividadSocio(IN p_id_socio INT) BEGIN END$$ DELIMITER ;
Desarrolle un procedimiento almacenado llamado reprogramarActividad que reciba como parámetros p_id_actividad INT y p_nueva_fecha DATE.
actividades.CURDATE()).ROLLBACK. Si todo sale bien, COMMIT.-- Escriba aquí el procedimiento: DELIMITER $$ CREATE PROCEDURE reprogramarActividad(IN p_id_actividad INT, IN p_nueva_fecha DATE) BEGIN END$$ DELIMITER ;
Desarrolle un procedimiento almacenado llamado reasignarActividadesSocio que reciba como parámetros p_id_socio_origen INT y p_id_socio_destino INT.
socios.actividades.id_socio en la tabla actividades).ROLLBACK y mostrar mensaje adecuado. Si todo sale bien, COMMIT y mostrar éxito.-- Escriba aquí el procedimiento: DELIMITER $$ CREATE PROCEDURE reasignarActividadesSocio(IN p_id_socio_origen INT, IN p_id_socio_destino INT) BEGIN END$$ DELIMITER ;
Desarrolle un procedimiento almacenado llamado cancelarActividadesFuturas que reciba como parámetro p_id_socio INT.
socios.CURDATE()).ROLLBACK y mostrar mensaje de error. Si todo sale bien, COMMIT y mostrar éxito.-- Escriba aquí el procedimiento: DELIMITER $$ CREATE PROCEDURE cancelarActividadesFuturas(IN p_id_socio INT) BEGIN END$$ DELIMITER ;