您好,UncleToo欢迎您!  为了更好的浏览本站,请使用高版本浏览器
RSS  Tag     设为首页 | 加入收藏
 您所在的位置:首页 > 数据库技术 > MySQL

MySQL存储过程中的错误处理

作者:UncleToo  来源:翻译  日期:2014-05-20 7:53:13
收藏  评论:( 2 )  阅读:1526

MySQL存储过程中的错误处理

       当MySQL执行存储过程遇到错误时,适当处理它,如继续执行或退出当前代码段,并返回有意义的错误提示是很重要的。一方面提高程序的容错能力,另一方便当程序出错时,开发人员也能准确定位错误的地方。

在本章MySQL教程中,我们将学习如何在存储过程中处理程序错误


声明处理程序

MySQL为我们提供了一种简单的方法定义处理程序,我们可以使用DECLARE HANDLER语句,如下所示:

DECLARE action HANDLER FOR condition_value statement;

如果其值与condition_value匹配,MySQL将执行statement,并且根据action值选择继续或退出当前代码块。

action 可以是以下两种:

  • CONTINUE:继续执行当前代码块

  • EXIT:退出当前代码块

condition_value 是一类特定的条件,可以使一下几种:

  • 一个MYSQL错误代码

  • 一个标准的SQLSTATE值,如SQLWARNING,NOTFOUND ,SQLEXCEPTION等

statement 是一个语句块,从BEGIN开始,到END结束。它可以是一个简单的sql语句,也可以是很复杂的逻辑语句。


MySQL错误处理的例子

例1:当程序发生错误,将has_error值置为1。如:

DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET has_error = 1;


例2:当遇到错误时,程序将回滚之前的操作,同时给出错误提示,然后退出当前程序块。如:

DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
Select '发生错误,执行将被回滚,程序将终止执行';
END;


例3:对于游标或select into操作,如果出现找不到记录的情况,将no_row_found赋值为1。如:

DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_row_found = 1;


例4:如果出现重复键值,MySQL会给出1062的错误,将给出错误提示,程序继续运行。如:

DECLARE CONTINUE HANDLER FOR 1062
Select '错误:重复键值';


在存储过程中MySQL的处理程序的例子

首先我们创建一张数据表,为测试所用。

Create TABLE article_tags(
    article_id INT,
    tag_id     INT,
    PRIMARY KEY(article_id,tag_id)
);

article_tags表用来存储文章及标签之间的关系(多对多)。article_id存储文章ID,tag_id存储标签ID


其次,我们创建一个存储过程,实现插入文章ID和标签ID。

DELIMITER $$
Create PROCEDURE insert_article_tags(IN article_id INT, IN tag_id INT)
BEGIN
    DECLARE CONTINUE HANDLER FOR 1062
    Select CONCAT('错误:重复键值 (',article_id,',',tag_id,')') AS msg;
    -- 插入新的记录
    Insert INTO article_tags(article_id,tag_id)
    VALUES(article_id,tag_id);
    -- 返回标签数量
    Select COUNT(*) FROM article_tags;
END


第三,利用存储过程往article_tags表添加一些数据

CALL insert_article_tags(1,1);
CALL insert_article_tags(1,2);
CALL insert_article_tags(1,3);


第四,这一步,我们添加一条已经存在的数据,看看上面定义的错误处理会不会执行。

CALL insert_article_tags(1,3);

执行这条语句后,我们会看到如下的错误提示。但是,因为在错误处理程序中我们设置了CONTINUE,因此程序还会继续执行,所以最后我们还会看到标签的数量。如下图:

如果我们将CONTINUE改为EXIT,如:

DELIMITER $$
Create PROCEDURE insert_article_tags_2(IN article_id INT, IN tag_id INT)
BEGIN
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    Select 'SQLException异常调用' AS msg;
    DECLARE EXIT HANDLER FOR 1062
        Select 'MySQL错误代码:1062' AS msg;
    DECLARE EXIT HANDLER FOR SQLSTATE '23000'
    Select 'SQLSTATE:23000' AS msg;
    -- 插入数据
    Insert INTO article_tags(article_id,tag_id)
       VALUES(article_id,tag_id);
    -- 返回记录数
    Select COUNT(*) FROM article_tags;
END

现在,我们再次插入一条已存在的数据:

CALL insert_article_tags_2(1,3);

这时,我们将智能看到错误信息,而看不到返回的记录数。


MySQL处理程序的优先级

在实际开发过程中,肯定会有多个错误处理程序,此时MySQL就需要根据优先级来调用处理。

在MySQL中,每一个error错误都会对应一个错误代码,一个SQLSTATE状态可以映射到MySQL多个错误代码,不太具体,而像SQLEXCPETION或SQLWARNING是一类SQLSTATES值,是通用的。因此,在处理优先级上,error错误首先处理,其次是SQLSTATE,最后是SQLEXCEPTION。


下面我们看一个包含这三种错误的存储过程:

ELIMITER $$
Create PROCEDURE insert_article_tags_3(IN article_id INT, IN tag_id INT)
BEGIN
    DECLARE EXIT HANDLER FOR 1062 Select '键值重复';
    DECLARE EXIT HANDLER FOR SQLEXCEPTION Select 'SQLException异常';
    DECLARE EXIT HANDLER FOR SQLSTATE '23000' Select 'SQLSTATE 23000';
    -- 插入记录
    Insert INTO article_tags(article_id,tag_id)
    VALUES(article_id,tag_id);
    -- 返回记录数
    Select COUNT(*) FROM article_tags;
END

现在,我们插入一条已经存在的记录:

CALL insert_article_tags_3(1,3);

按照上面介绍的处理顺序,此时应该提示“键值重复”。如下图:


命名错误

首先我们看一个例子:

DECLARE EXIT HANDLER FOR 1051 Select '请先创建数据表 abc';
Select * FROM abc;

当我们查询一张不存在的的表时,提示相关错误信息,这里我们用到了1051代码。想想一下,MySQL中有相当多的错误代码,难道我们需要记住每一个吗?

当然不是,MySQL为我们提供了DECLARE CONDITION语句,用于命名错误条件,如:

DECLARE condition_name CONDITION FOR condition_value;

condition_value是一个错误代码,如1015或SQLSTATE值。

定义之后,我们就可以使用condition_name来代替condition_value。现在,我们将上面的脚本重写,如:

DECLARE table_not_found CONDITION for 1051;
DECLARE EXIT HANDLER FOR  table_not_found Select '请先创建数据表 abc';
Select * FROM abc;

很显然,这段代码可读性比上面的要好。


原文(英文)地址:http://www.mysqltutorial.org/mysql-error-handling-in-stored-procedures/



除非特别声明,本站所有PHP教程及其他教程/文章均为原创、翻译或网友投稿,版权均归UncleToo中文网所有, 转载请注明作者及出处。
原文网址:http://www.uncletoo.com/html/mysql/953.html
读完这篇文章后,你是否有所收获? 分享是一种生活的信念!
  • 0
  • 0
我来说两句
更多>>网友评论