MySQL情况处理(存储程序中对异常情况进行处理)

数据库 专栏收录该内容
95 篇文章 0 订阅

存储的程序执行过程中可能出现需要特殊处理的情况,例如退出当前程序块或继续执行。可以为一般条件(如警告或异常)或特定条件(如特定错误代码)定义处理程序。特定条件可以在处理程序中指定名称并以这种方式引用。

若要命名条件,请使用DECLARE ... CONDITION声明。若要声明处理程序,请使用DECLARE ... HANDLER声明。看见第13.6.7.1节,“宣布.条件陈述“,和第13.6.7.2节,“宣布.处理程序语句“...有关在发生条件时服务器如何选择处理程序的信息,请参阅第13.6.7.6节,“处理程序的范围规则”.

若要引发条件,请使用SIGNAL声明。若要修改条件处理程序中的条件信息,请使用RESIGNAL...看见第13.6.7.1节,“宣布.条件陈述“,和第13.6.7.2节,“宣布.处理程序语句“.

若要从诊断区域检索信息,请使用GET DIAGNOSTICS声明(见第13.6.7.3节,“获取诊断声明”)。有关诊断区域的信息,请参阅13.6.7.7节,“MySQL诊断区域”.

13.6.7.1宣布..。条件语句

DECLARE condition_name CONDITION FOR condition_value

condition_value: {
    mysql_error_code
  | SQLSTATE [VALUE] sqlstate_value
}

这个DECLARE ... CONDITION语句声明一个命名错误条件,将名称与需要特定处理的条件关联起来。名称可以在后续的DECLARE ... HANDLER声明(见第13.6.7.2节,“宣布.处理程序语句“).

条件声明必须出现在游标或处理程序声明之前。

这个condition_valueDECLARE ... CONDITION指示要与条件名称关联的特定条件或条件类。它可以采取以下形式:

  • mysql_error_code表示MySQL错误代码的整数文本。

    不要使用MySQL错误代码0,因为这表示成功,而不是错误条件。有关MySQL错误代码的列表,请参见第B.3.1节,“服务器错误消息参考”.

  • SQLSTATE[值]sqlstate_value::指示SQLSTATE值的5个字符字符串文字。

    不要使用以'00'因为这些表示成功,而不是错误条件。有关SQLSTATE值的列表,请参见第B.3.1节,“服务器错误消息参考”.

中所指的条件名称SIGNAL或使用RESIGNAL语句必须与SQLSTATE值相关联,而不是MySQL错误代码。

使用条件名称可以帮助使存储的程序代码更清晰。例如,这个处理程序适用于删除一个不存在的表的尝试,但只有当您知道1051是mysql错误代码时,这一点才是显而易见的。“未知表”:

DECLARE CONTINUE HANDLER FOR 1051
  BEGIN
    -- body of handler
  END;

通过为条件声明名称,可以更容易地看出处理程序的用途:

DECLARE no_such_table CONDITION FOR 1051;
DECLARE CONTINUE HANDLER FOR no_such_table
  BEGIN
    -- body of handler
  END;

下面是同一个条件的命名条件,但是基于相应的SQLSTATE值,而不是MySQL错误代码:

DECLARE no_such_table CONDITION FOR SQLSTATE '42S02';
DECLARE CONTINUE HANDLER FOR no_such_table
  BEGIN
    -- body of handler
END;

13.6.7.2宣布..。处理程序语句

DECLARE handler_action HANDLER
    FOR condition_value [, condition_value] ...
    statement

handler_action: {
    CONTINUE
  | EXIT
  | UNDO
}

condition_value: {
    mysql_error_code
  | SQLSTATE [VALUE] sqlstate_value
  | condition_name
  | SQLWARNING
  | NOT FOUND
  | SQLEXCEPTION
}

这个DECLARE ... HANDLER语句指定处理一个或多个条件的处理程序。如果出现这些条件之一,则指定statement执行。statement可以是一个简单的语句,例如SET var_name = value,或使用以下方法编写的复合语句BEGINEND(见第13.6.1节,“开始.结束复合语句“).

处理程序声明必须出现在变量或条件声明之后。

这个handler_action值指示处理程序在执行处理程序语句后采取的操作:

  • CONTINUE*继续执行当前程序。

  • EXIT::执行将终止BEGIN ... END声明处理程序的复合语句。即使条件发生在内部块中,也是如此。

  • UNDO*不支持。

这个condition_valueDECLARE ... HANDLER指示激活处理程序的特定条件或条件类。它可以采取以下形式:

  • mysql_error_code:表示MySQL错误代码的整数文本,例如用于指定的1051“未知表”:

    DECLARE CONTINUE HANDLER FOR 1051
      BEGIN
        -- body of handler
      END;

    不要使用MySQL错误代码0,因为这表示成功,而不是错误条件。有关MySQL错误代码的列表,请参见第B.3.1节,“服务器错误消息参考”.

  • SQLSTATE[值]sqlstate_value::指示SQLSTATE值的5个字符字符串文字,如'42S01'指定“未知表”:

    DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
      BEGIN
        -- body of handler
      END;

    不要使用以'00'因为这些表示成功,而不是错误条件。有关SQLSTATE值的列表,请参见第B.3.1节,“服务器错误消息参考”.

  • condition_name*以前用DECLARE ... CONDITION...条件名称可以与MySQL错误代码或SQLSTATE值相关联。看见第13.6.7.1节,“宣布.条件陈述“.

  • SQLWARNING::SQLSTATE值类的缩写,以'01'.

    DECLARE CONTINUE HANDLER FOR SQLWARNING
      BEGIN
        -- body of handler
      END;
  • NOT FOUND::SQLSTATE值类的缩写,以'02'...这在游标上下文中是相关的,并用于控制游标到达数据集末尾时发生的情况。如果没有更多的行可用,则使用SQLSTATE值出现无数据条件'02000'...若要检测此条件,可以为此设置一个处理程序,也可以为NOT FOUND条件。

    DECLARE CONTINUE HANDLER FOR NOT FOUND
      BEGIN
        -- body of handler
      END;

    有关另一个示例,请参见第13.6.6节,“游标”...这个NOT FOUND条件也发生在SELECT ... INTO var_list不检索行的语句。

  • SQLEXCEPTION::SQLSTATE值类的缩写,它不是以'00''01',或'02'.

    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
      BEGIN
        -- body of handler
    END;

有关在发生条件时服务器如何选择处理程序的信息,请参阅第13.6.7.6节,“处理程序的范围规则”.

如果发生未声明处理程序的条件,则所采取的操作取决于条件类:

  • SQLEXCEPTION条件时,存储的程序终止于引发条件的语句,就好像存在EXIT处理程序。如果程序是由另一个存储程序调用的,则调用程序使用应用于其自己处理程序的处理程序选择规则来处理该条件。

  • SQLWARNING条件下,程序继续执行,就好像有一个CONTINUE处理程序。

  • NOT FOUND条件,如果该条件是正常提出的,则操作是CONTINUE...如果它是由SIGNALRESIGNAL,行动是EXIT.

下面的示例使用处理程序SQLSTATE '23000',它发生于重复键错误:

mysql> CREATE TABLE test.t (s1 INT, PRIMARY KEY (s1));
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter //

mysql> CREATE PROCEDURE handlerdemo ()
       BEGIN
         DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;
         SET @x = 1;
         INSERT INTO test.t VALUES (1);
         SET @x = 2;
         INSERT INTO test.t VALUES (1);
         SET @x = 3;
       END;
       //
Query OK, 0 rows affected (0.00 sec)

mysql> CALL handlerdemo()//
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @x//
    +------+
    | @x   |
    +------+
    | 3    |
    +------+
    1 row in set (0.00 sec)

注意@x3在过程执行之后,这表明在错误发生后,执行一直持续到过程的末尾。如果DECLARE ... HANDLER语句时,MySQL将采取默认操作(EXIT)第二次之后INSERT失败的原因是PRIMARY KEY约束,以及SELECT @x会回来的2.

若要忽略条件,请声明CONTINUE处理程序,并将其与空块关联。例如:

DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;

块标签的作用域不包括在块中声明的处理程序的代码。因此,与处理程序关联的语句不能使用ITERATELEAVE若要引用包含处理程序声明的块的标签,请执行以下操作。考虑以下示例,其中REPEAT块的标签为retry:

CREATE PROCEDURE p ()
BEGIN
  DECLARE i INT DEFAULT 3;
  retry:
    REPEAT
      BEGIN
        DECLARE CONTINUE HANDLER FOR SQLWARNING
          BEGIN
            ITERATE retry;    # illegal
          END;
        IF i < 0 THEN
          LEAVE retry;        # legal
        END IF;
        SET i = i - 1;
      END;
    UNTIL FALSE END REPEAT;
END;

这个retry标签位于IF语句在块中。不属于CONTINUE处理程序,因此那里的引用无效,并导致错误:

ERROR 1308 (42000): LEAVE with no matching label: retry

为了避免在处理程序中引用外部标签,请使用以下策略之一:

  • 若要离开块,请使用EXIT处理程序。如果不需要清除块,则BEGIN ... END处理程序体可以是空的:

    DECLARE EXIT HANDLER FOR SQLWARNING BEGIN END;

    否则,将清理语句放在处理程序主体中:

    DECLARE EXIT HANDLER FOR SQLWARNING
      BEGIN
        block cleanup statements
      END;
    
  • 若要继续执行,请在CONTINUE可以在封闭块中检查以确定是否调用了处理程序的处理程序。下面的示例使用变量done为此目的:

    CREATE PROCEDURE p ()
    BEGIN
      DECLARE i INT DEFAULT 3;
      DECLARE done INT DEFAULT FALSE;
      retry:
        REPEAT
          BEGIN
            DECLARE CONTINUE HANDLER FOR SQLWARNING
              BEGIN
                SET done = TRUE;
              END;
            IF done OR i < 0 THEN
              LEAVE retry;
            END IF;
            SET i = i - 1;
          END;
        UNTIL FALSE END REPEAT;
    END;

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值