Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 Reference Manual  /  ...  /  DECLARE ... HANDLER Statement

15.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 编写的复合语句(见第15.6.1节,“BEGIN ... END 复合语句”)。

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

handler_action 值指示处理程序执行完毕后的操作:

  • CONTINUE:当前程序的执行继续。

  • EXIT:在声明了处理程序的 BEGIN ... END 复合语句中,执行终止。这也适用于条件发生在内层块中。

  • UNDO:不支持。

DECLARE ... HANDLER中,condition_value 指定激活处理程序的特定条件或条件类别。它可以以以下形式出现:

  • mysql_error_code:一个整数字面量,表示 MySQL 错误代码,例如指定 未知表

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

    不要使用 MySQL 错误代码 0,因为那表示成功,而不是错误条件。关于 MySQL 错误代码的列表,请参见服务器错误消息参考

  • SQLSTATE [VALUE] sqlstate_value:一个 5 个字符字面量,表示 SQLSTATE 值,例如指定 '42S01',表示 未知表

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

    不要使用以 '00' 开头的 SQLSTATE 值,因为那表示成功,而不是错误条件。关于 SQLSTATE 值的列表,请参见服务器错误消息参考

  • condition_name:之前使用DECLARE ... CONDITION指定的条件名称。条件名称可以与 MySQL 错误代码或 SQLSTATE 值相关联。请参见第15.6.7.1节,“DECLARE ... CONDITION 语句”

  • 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;

    另一个示例,请见第15.6.6节,“游标”NOT FOUND 情况也会出现于 SELECT ... INTO var_list 语句中,如果没有检索到行。

  • SQLEXCEPTION:简写 SQLSTATE 值的类别,值不以 '00''01''02' 开头。

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

关于服务器在条件出现时选择处理程序的信息,请见第15.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)

注意,@x 在程序执行完毕后是3,显示了在错误发生后程序继续执行到程序结尾。如果没有DECLARE ... HANDLER语句,MySQL 将在第二个INSERT失败时由于PRIMARY KEY约束而退出,并且SELECT @x 将返回2

要忽略一个条件,声明一个CONTINUE处理器并将其与空块关联。例如:

DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;

块标签的作用域不包括在块中声明的处理程序代码。因此,关联处理程序语句不能使用ITERATELEAVE来引用块中的标签。考虑以下示例,where theREPEAT块的标签为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;
  • 要继续执行,设置在封闭块中的状态变量,以确定是否调用了处理程序。以下示例使用变量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;