DECLARE HANDLER
DECLARE HANDLER define qué debe hacer MySQL cuando ocurre una condición específica durante la ejecución de un procedimiento almacenado. Es el mecanismo principal de manejo de errores, similar al try-catch de otros lenguajes.
Sintaxis
DECLARE tipo_handler HANDLER
FOR condicion [, condicion ...]
sentencia;Tipos de handler
| Tipo | Comportamiento |
|---|---|
| CONTINUE | Ejecuta la sentencia del handler y continúa la ejecución |
| EXIT | Ejecuta la sentencia del handler y sale del bloque BEGIN...END actual |
Condiciones que se pueden manejar
| Condición | Descripción |
|---|---|
| SQLSTATE 'valor' | Un código SQLSTATE específico |
| mysql_error_code | Un código de error numérico de MySQL |
| SQLWARNING | Cualquier SQLSTATE que empiece con '01' |
| NOT FOUND | SQLSTATE '02000', usado con cursores |
| SQLEXCEPTION | Cualquier SQLSTATE que no empiece con '00', '01' o '02' |
| nombre_condicion | Una condición definida con DECLARE CONDITION |
CONTINUE HANDLER
DELIMITER //
CREATE PROCEDURE insertar_con_handler()
BEGIN
DECLARE v_error BOOLEAN DEFAULT FALSE;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
SET v_error = TRUE;
-- Intentar insertar un duplicado (si hay UNIQUE en email)
INSERT INTO clientes (nombre, apellidos, email, ciudad, telefono)
VALUES ('Test', 'Handler', 'maria.garcia@email.com', 'Madrid', '600000000');
IF v_error THEN
SELECT 'Error: no se pudo insertar el registro' AS mensaje;
ELSE
SELECT 'Registro insertado correctamente' AS mensaje;
END IF;
END //
DELIMITER ;CALL insertar_con_handler();| mensaje |
|---|
| Error: no se pudo insertar el registro |
La ejecución continúa después del error porque usamos CONTINUE HANDLER.
EXIT HANDLER
DELIMITER //
CREATE PROCEDURE exit_handler_ejemplo()
BEGIN
DECLARE v_resultado VARCHAR(100) DEFAULT 'No ejecutado';
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SET v_resultado = 'Error capturado, saliendo del bloque';
END;
-- Esto genera un error (tabla inexistente)
INSERT INTO tabla_inexistente VALUES (1);
-- Esta línea NO se ejecuta con EXIT HANDLER
SET v_resultado = 'Insert exitoso';
END;
SELECT v_resultado AS resultado;
END //
DELIMITER ;CALL exit_handler_ejemplo();| resultado |
|---|
| Error capturado, saliendo del bloque |
Handler para errores específicos
DELIMITER //
CREATE PROCEDURE manejar_duplicado(IN p_email VARCHAR(100))
BEGIN
DECLARE v_mensaje VARCHAR(200);
-- Error 1062: Duplicate entry
DECLARE CONTINUE HANDLER FOR 1062
SET v_mensaje = CONCAT('El email ', p_email, ' ya existe');
INSERT INTO clientes (nombre, apellidos, email, ciudad, telefono)
VALUES ('Nuevo', 'Cliente', p_email, 'Madrid', '600000000');
IF v_mensaje IS NULL THEN
SET v_mensaje = 'Cliente insertado correctamente';
END IF;
SELECT v_mensaje AS resultado;
END //
DELIMITER ;CALL manejar_duplicado('maria.garcia@email.com');| resultado |
|---|
| El email maria.garcia@email.com ya existe |
Handler con SQLSTATE
DELIMITER //
CREATE PROCEDURE handler_sqlstate()
BEGIN
DECLARE v_msg VARCHAR(200);
-- SQLSTATE 23000: Integrity constraint violation
DECLARE CONTINUE HANDLER FOR SQLSTATE '23000'
SET v_msg = 'Violación de restricción de integridad';
-- Intentar insertar con FK inválida
INSERT INTO pedidos (cliente_id, fecha, total, estado)
VALUES (9999, CURDATE(), 100.00, 'pendiente');
IF v_msg IS NOT NULL THEN
SELECT v_msg AS error;
END IF;
END //
DELIMITER ;Handler con bloque BEGIN...END
El handler puede ejecutar múltiples sentencias:
DELIMITER //
CREATE PROCEDURE handler_complejo()
BEGIN
DECLARE v_error_code INT;
DECLARE v_error_msg VARCHAR(200);
DECLARE v_tiene_error BOOLEAN DEFAULT FALSE;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
v_error_code = MYSQL_ERRNO,
v_error_msg = MESSAGE_TEXT;
SET v_tiene_error = TRUE;
END;
-- Operación que podría fallar
INSERT INTO tabla_inexistente VALUES (1);
IF v_tiene_error THEN
SELECT v_error_code AS codigo, v_error_msg AS mensaje;
END IF;
END //
DELIMITER ;CALL handler_complejo();| codigo | mensaje |
|---|---|
| 1146 | Table 'tienda_mysql.tabla_inexistente' doesn't exist |
Múltiples handlers
DELIMITER //
CREATE PROCEDURE multiples_handlers()
BEGIN
DECLARE v_msg VARCHAR(200) DEFAULT 'OK';
DECLARE CONTINUE HANDLER FOR 1062
SET v_msg = 'Registro duplicado';
DECLARE CONTINUE HANDLER FOR 1452
SET v_msg = 'Clave foránea no válida';
DECLARE CONTINUE HANDLER FOR SQLWARNING
SET v_msg = 'Advertencia detectada';
-- Lógica del procedimiento...
SELECT v_msg AS estado;
END //
DELIMITER ;Prioridad de handlers
Cuando ocurre un error, MySQL busca el handler más específico:
- Código de error MySQL específico
- SQLSTATE específico
- SQLEXCEPTION, SQLWARNING o NOT FOUND
Limpieza
DROP PROCEDURE IF EXISTS insertar_con_handler;
DROP PROCEDURE IF EXISTS exit_handler_ejemplo;
DROP PROCEDURE IF EXISTS manejar_duplicado;
DROP PROCEDURE IF EXISTS handler_sqlstate;
DROP PROCEDURE IF EXISTS handler_complejo;
DROP PROCEDURE IF EXISTS multiples_handlers;En el siguiente artículo veremos DECLARE CONDITION para dar nombres legibles a las condiciones de error.
Escrito por Eduardo Lázaro
