MySQL 存储过程中的错误处理实例
第一步:建一个表
CREATE TABLE article_tags(
article_id INT,
tag_id INT,
PRIMARY KEY(article_id,tag_id)
);
第二步:建立存储过程insert_article_tags
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 $$
第三步:插入正常数据
CALL insert_article_tags(1,1);
CALL insert_article_tags(1,2);
CALL insert_article_tags(1,3);
第四步:异常数据处理(有主键约束,报错了)
CALL insert_article_tags(1,3);
第五步:测试其他异常及运行级别顺序():
DECLARE EXIT HANDLER FOR 1062
SELECT 'MySQL error code 1062 invoked as errmsg';
DECLARE EXIT HANDLER FOR SQLSTATE '23000'
SELECT 'SQLSTATE 23000 invoked' as errmsg;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
SELECT 'MySQL error code 1062 invoked as errmsg';
5.1创建存储过程
DELIMITER $$
CREATE PROCEDURE insert_article_tags_2(IN article_id INT, IN tag_id INT)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
SELECT 'SQLException invoked ' as errmsg;
DECLARE EXIT HANDLER FOR 1062
SELECT 'MySQL error code 1062 invoked' as errmsg;
DECLARE EXIT HANDLER FOR SQLSTATE '23000'
SELECT 'SQLSTATE 23000 invoked' as errmsg;
-- 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 $$
5.2测试结果
CALL insert_article_tags_2(1,3);
结果为:
MySQL error code 1062 invoked
分别屏蔽存储过程如下insert_article_tags_2中
/* DECLARE EXIT HANDLER FOR SQLEXCEPTION
SELECT 'SQLException invoked ’ as errmsg;*/
/DECLARE EXIT HANDLER FOR 1062
SELECT ‘MySQL error code 1062 invoked’ as errmsg;/
/DECLARE EXIT HANDLER FOR SQLSTATE ‘23000’
SELECT ‘SQLSTATE 23000 invoked’ as errmsg;/
测试最中结果 优先级:【FOR 1062 】>【FOR SQLSTATE ‘23000’】>【FOR SQLEXCEPTION 】
6.异常回滚或继续执行
CREATE DEFINER=root
@%
PROCEDURE insert_article_tags_3
(IN article_id INT, IN tag_id INT)
BEGIN
DECLARE has_error int(11);
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SELECT 'An error has occurred, operation rollbacked and the stored procedure was terminated' as errmsg;
END;
/*DECLARE EXIT HANDLER FOR SQLSTATE '23000'
SELECT 'SQLSTATE 23000 invoked' as errmsg;*/
-- 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
7.异常条件判断
CREATE DEFINER=`root`@`%` PROCEDURE `insert_article_tags_5`(IN article_id INT, IN tag_id INT)
BEGIN
DECLARE has_error int(11);
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SELECT 'An error has occurred, operation rollbacked and the stored procedure was terminated' as errmsg;
END;
DECLARE CONTINUE HANDLER FOR 1062 SET has_error = 5;
SELECT 'MySQL error code 1062 invoked' as errmsg;
/*DECLARE EXIT HANDLER FOR SQLSTATE '23000'
SELECT 'SQLSTATE 23000 invoked' as errmsg;*/
-- 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;
IF has_error <> 5 THEN
SELECT CONCAT('ERR0R ', has_error) as msg;
ELSE
SELECT CONCAT('正常 ', has_error) as msg;
END IF;
END
运行结果:
CALL insert_article_tags_5(1,3);
Result1: MySQL error code 1062 invoked
Result2: 4
Result3: ERR0R 5
注意:别把异常判断放在了出现异常的前面,如存储过程insert_article_tags_4就是错误的,这样就找不到has_error值了
8.游标示例
CREATE TABLE `t_users`
(
`ID` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_name` VARCHAR(60),
`user_pass` VARCHAR(64),
PRIMARY KEY (`ID`)
);
INSERT INTO t_users VALUES(null,'sheng','sheng123'),
(null,'yu','yu123'),
(null,'ling','ling123');
DELIMITER //
DROP PROCEDURE test_cursor ;
CREATE PROCEDURE test_cursor (out result varchar(100))
BEGIN
DECLARE name VARCHAR(20);
DECLARE pass VARCHAR(20);
DECLARE done INT;
DECLARE cur_test CURSOR FOR SELECT user_name,user_pass FROM t_users;
DECLARE continue handler FOR SQLSTATE '02000' SET done = 1;
OPEN cur_test;
repeat
FETCH cur_test into name,pass;
SELECT concat(',',name,pass);
until done
END repeat;
CLOSE cur_test;
END //
call test_cursor(@test)
select @test