Control de errores en procedimientos almacenados con transacciones en Mysql

En el siguiente articulo se describe la forma de tratar errores en transacciones con procedimientos almacenados en Mysql. Esto es muy útil cuando tienes procedimientos que llaman a otro procedimiento o a alguna función de usuario en Mysql. Y que conseguimos ? pues que en caso de que algunas de las consultas o llamadas a otro procedimiento falle podamos deshacer el cambio sin que afecte la base de datos y ademas el error se propague por los diferentes niveles de procedimientos. Esto es gracias a la instrucción RESIGNAL de Mysql

mysql-logo

Para esta prueba necesitaremos la base de datos Northwind (si buscan en google la encuentras facilmente)  y los procedimientos test y test2 que se presentan a continuación

CREATE DEFINER=`root`@`localhost` PROCEDURE `test`()
begin
 
 DECLARE EXIT HANDLER FOR SQLEXCEPTION
 BEGIN
 SHOW ERRORS LIMIT 1;
 ROLLBACK;
 END; 
 DECLARE EXIT HANDLER FOR SQLWARNING
 BEGIN
 SHOW WARNINGS LIMIT 1;
 ROLLBACK;
 END;

 
START TRANSACTION;
 
 call test2();
select * from Products where UnitsInStock =0;
COMMIT;

end

Sección DECLARE EXIT HANDLER FOR SQLEXCEPTION

Como es normal en mysql la sección empieza con un begin y acaba con end ( en vez de parentesis, el compilador de mysql usa estos delimitadores). Lo que está dentro de este código es lo que se ejecutará en caso de una excepción de mysql. Nosotros le estamos diciendo que nos muestre el error y que además haga un rollback de la transacción si es que se ha ejecutado algo. Si quisieramos lanzar una consulta u otro precedimiento este seria el lugar.

Sección DECLARE EXIT HANDLER FOR SQLWARNING

Es similar al anterior pero salta cuando hay un warning de sql. Los warnings pueden saltar por ejemplo al insertar un registro null cuando su campo no le permite etc. Imaginate lo que pasa si haces update de cientos de registros que dependen de un valor de una variable que vino null o mal iniciada.. desastre.

RESIGNAL. Esto hace que el error se propague a la función o procedimiento que llamó este procedimiento. Es importante ponerlo, si no lo pones como el error salta en test2 no llegará a test1 y para test1 no habrá ocurrido ningún error por lo que continuará con su ejecución normal y ejecutaría el commit de la transacción que en este caso es un simple select pero podria ser un insert, un update o un delete o cualquier cosa.

START TRANSACTION

Esta instrucción es donde empieza la transacción y va a ejecutar todo el código que hay desde ahí hasta el commit. Cualquier cosa que se haya modificado dentro de esta estructura si hay algún error saltará la excepción de Mysql y deshará los cambios;

CREATE DEFINER=`root`@`localhost` PROCEDURE `test2`()
begin

 DECLARE EXIT HANDLER FOR SQLEXCEPTION
 BEGIN
 SHOW ERRORS LIMIT 1;
RESIGNAL;
 ROLLBACK;
 END; 
 DECLARE EXIT HANDLER FOR SQLWARNING
 BEGIN
 SHOW WARNINGS LIMIT 1;
RESIGNAL;
 ROLLBACK;
 END;
START TRANSACTION;
 insert into Products (ProductId) values(null);

commit;
END

Si llamamos al precedimiento test() con call test() este realmente no hace nada simplemente llama al procedimiento test2(), el cual intenta hacer un insert en la tabla Products, pero como no admite null en el campo ProductName salta un warning que se propaga al primer procedimiento (test()) y este lo muestra por pantalla porque captura el error proveniente de resignal.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s