MySQL的存储过程错误捕获方式和Oracle的有很大的不同。
MySQL中可以使用DECLARE关键字来定义处理程序。其基本语法如下:
DECLARE handler_type HANDLER FOR condition_value[,...] sp_statement handler_type: CONTINUE | EXIT condition_value: SQLSTATE [VALUE] sqlstate_value | condition_name | SQLWARNING | NOT FOUND | SQLEXCEPTION | mysql_error_code
handler_type参数指明错误的处理方式,该参数有2个取值。这1个取值分别是CONTINUE、EXIT
CONTINUE表示遇到错误,执行预先定义的方式,继续向下执行;
EXIT表示遇到错误后,执行预先定义的方式,马上退出;
注意:通常情况下,执行过程中遇到错误应该立刻停止执行下面的语句,并且撤回前面的操作。
condition_value参数指明错误类型,该参数有6个取值。
sqlstate_value和mysql_error_code与条件定义中的是同一个意思。
condition_name是DECLARE定义的条件名称。
SQLWARNING表示所有以01开头的sqlstate_value值。
NOT FOUND表示所有以02开头的sqlstate_value值。
SQLEXCEPTION表示所有没有被SQLWARNING或NOT FOUND捕获的sqlstate_value值。
sp_statement表示一些存储过程或函数的执行语句。
下面是定义处理程序的几种方式。代码如下:
//方法一:捕获sqlstate_value DECLARE CONTINUE HANDLER FOR SQLSTATE '42000' SET @info='CAN NOT FIND'; //方法二:捕获mysql_error_code DECLARE CONTINUE HANDLER FOR 1148SET @info='CAN NOT FIND'; //方法三:先定义条件,然后调用 DECLARE can_not_find CONDITION FOR 1146 ; DECLARE CONTINUE HANDLER FOR can_not_find SET @info='CAN NOT FIND'; //方法四:使用SQLWARNING DECLARE EXIT HANDLER FOR SQLWARNING SET @info='ERROR'; //方法五:使用NOT FOUND DECLARE EXIT HANDLER FOR NOT FOUND SET @info='CAN NOT FIND'; //方法六:使用SQLEXCEPTION DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info='ERROR';
上述代码是6种定义处理程序的方法。
第一种方法是捕获sqlstate_value值。如果遇到sqlstate_value值为42000,执行CONTINUE操作,并且输出"CAN NOT FIND"信息。
第二种方法是捕获mysql_error_code值。如果遇到mysql_error_code值为1148,执行CONTINUE操作,并且输出"CAN NOT FIND"信息。
第三种方法是先定义条件,然后再调用条件。这里先定义can_not_find条件,遇到1148错误就执行CONTINUE操作。
第四种方法是使用SQLWARNING。SQLWARNING捕获所有以01开头的sqlstate_value值,然后执行EXIT操作,并且输出"ERROR"信息。
第五种方法是使用NOT FOUND。NOT FOUND捕获所有以02开头的sqlstate_value值,然后执行EXIT操作,并且输出"CAN NOT FIND"信息。
第六种方法是使用SQLEXCEPTION。SQLEXCEPTION捕获所有没有被SQLWARNING或NOT FOUND捕获的sqlstate_value值。
单句的
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_row_found = 1;
DECLARE CONTINUE HANDLER FOR 1062 SELECT 'Error, duplicate key occurred';
如果错误捕获的时候要做的操作比较多可以这样
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; SELECT 'An error has occurred, operation rollbacked and the stored procedure was terminated'; END;
example:
CREATE TABLE `article_tags` ( `article_id` int(11) NOT NULL DEFAULT '0', `tag_id` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`article_id`,`tag_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DELIMITER $$ CREATE PROCEDURE insert_article_tags(IN article_id INT, IN tag_id INT) BEGIN DECLARE CONTINUE HANDLER FOR 1062 SELECT CONCAT('duplicate keys (',article_id,',',tag_id,') found') AS msg; -- insert a new record into article_tags INSERT INTO article_tags(article_id,tag_id) VALUES(article_id,tag_id); -- return tag count for the article SELECT COUNT(*) FROM article_tags; END
mysql 抛出错误给调用程序
使用signal语句返回Error或warning给存储过程的调用者。
signal的语法:
SIGNAL SQLSTATE | condition_name SET condition_information_item_name_1 = value_1, condition_information_item_name_1 = value_2, etc;
使用SET设置返回的内容,如果要返回多个条件信息用逗号隔开。
RESIGNAL无论是功能上还是用法上和signal都很像,除了:
1.使用resignal的时候必须配合handler使用,否则会得到 “RESIGNAL when handler is not active”的报错,
然而signal可以在存储过程的任何地方使用。
2.可以漏掉resignal语句的所有属性,甚至是SQLSTATE value.
DELIMITER $$ CREATE PROCEDURE AddOrderItem( in orderNo int, in productCode varchar(45), in qty int, in price double, in lineNo int ) BEGIN DECLARE C INT; SELECT COUNT(orderNumber) INTO C FROM orders WHERE orderNumber = orderNo; -- check if orderNumber exists IF(C != 1) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Order No not found in orders table'; END IF; -- more code below -- ... END
DELIMITER $$ CREATE PROCEDURE Divide(IN numerator INT, IN denominator INT, OUT result double) BEGIN DECLARE division_by_zero CONDITION FOR SQLSTATE '22012'; DECLARE CONTINUE HANDLER FOR division_by_zero RESIGNAL SET MESSAGE_TEXT = 'Division by zero / Denominator cannot be zero'; -- IF denominator = 0 THEN SIGNAL division_by_zero; ELSE SET result := numerator / denominator; END IF; END
没有resignal 的时候调用存储过程:
DELIMITER $$ CREATE DEFINER=`root`@`localhost` PROCEDURE `insert_article_tags`(IN article_id INT, IN tag_id INT) BEGIN DECLARE CONTINUE HANDLER FOR 1062 begin insert into pro_log values('1062',CONCAT('duplicate keys (',article_id,',',tag_id,') found')); SELECT CONCAT('duplicate keys (',article_id,',',tag_id,') found') AS msg; -- resignal set message_text ='duplicate keys'; end ; -- declare continue handler for sqlexception -- SELECT 'SQLException invoked'; -- insert a new record into article_tags INSERT INTO article_tags(article_id,tag_id) VALUES(article_id,tag_id); -- return tag count for the article SELECT COUNT(*) FROM article_tags; END
测试调用
去掉注释的 resignal set。
继续测试
这样可以得到向外抛出的错误。
参考:
http://www.mysqltutorial.org/mysql-error-handling-in-stored-procedures/
http://www.mysqltutorial.org/mysql-signal-resignal/
http://www.cnblogs.com/lyhabc/p/3793524.html
http://www.zhdba.com/mysqlops/2013/08/31/mysql-handler-2/