#### 13.6.7.2 DECLARE ... HANDLER 语句

[](<>)

```
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.html)语句指定处理一个或多个条件的处理程序。如果出现这些情况之一，则指定*`陈述`*执行。*`陈述`*可以是一个简单的语句，例如`放 *`变量名`* = *`价值`*`, 或使用编写的复合语句`开始`和`结尾`（看[第 13.6.1 节，“BEGIN ... END 复合语句”](begin-end.html)）。

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

这*`handler_action`*value 指示处理程序在执行处理程序语句后采取的操作：

-   `继续`：继续执行当前程序。

-   `出口`: 执行终止[`开始...结束`](begin-end.html)声明处理程序的复合语句。即使条件发生在内部块中也是如此。

-   `撤消`： 不支持。

    这*`条件值`*为了[`声明...处理程序`](declare-handler.html)指示激活处理程序的特定条件或条件类别。它可以采取以下形式：

-   *`mysql_error_code`*: 表示 MySQL 错误代码的整数文字，例如 1051 来指定“未知表”：

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

    不要使用 MySQL 错误代码 0，因为这表示成功而不是错误条件。有关 MySQL 错误代码的列表，请参阅[服务器错误消息参考](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html).

-   SQLSTATE[价值] *`sqlstate_value`*: 一个 5 字符的字符串文字，指示 SQLSTATE 值，例如`'42S01'`指定“未知表”：

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

    不要使用以`'00'`因为那些表示成功而不是错误情况。有关 SQLSTATE 值的列表，请参见[服务器错误消息参考](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html).

-   *`条件名称`*：先前指定的条件名称[`声明...条件`](declare-condition.html).条件名称可以与 MySQL 错误代码或 SQLSTATE 值相关联。看[第 13.6.7.1 节，“DECLARE ... CONDITION 语句”](declare-condition.html).

-   `SQL警告`: 以开头的 SQLSTATE 值类的简写`'01'`.

    ```
    DECLARE CONTINUE HANDLER FOR SQLWARNING
      BEGIN
        -- body of handler
      END;
    ```

-   `未找到`: 以开头的 SQLSTATE 值类的简写`'02'`.这与游标的上下文相关，用于控制游标到达数据集末尾时发生的情况。如果没有更多行可用，则使用 SQLSTATE 值出现无数据条件`'02000'`.要检测这种情况，您可以为其设置处理程序或为`未找到`健康）状况。

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

    另一个例子，见[第 13.6.6 节，“光标”](cursors.html).这`未找到`条件也发生在`选择 ... 进入 *`var_list`*`不检索行的语句。

-   `SQL异常`: 不以开头的 SQLSTATE 值类的简写`'00'`,`'01'`， 要么`'02'`.

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

    有关在条件发生时服务器如何选择处理程序的信息，请参阅[第 13.6.7.6 节，“处理程序的范围规则”](handler-scope.html).

    如果发生了没有声明处理程序的条件，则采取的操作取决于条件类：

-   为了`SQL异常`条件，存储的程序在引发条件的语句处终止，就好像有一个`出口`处理程序。如果该程序被另一个存储的程序调用，则调用程序使用应用于其自己的处理程序的处理程序选择规则来处理该条件。

-   为了`SQL警告`条件下，程序继续执行，就好像有一个`继续`处理程序。

-   为了`未找到`条件，如果条件被正常提出，动作是`继续`.如果它是由[`信号`](signal.html)要么[`重新信号`](resignal.html), 动作是`出口`.

    以下示例使用处理程序`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`after the procedure executes ，说明在发生错误后继续执行到过程结束。如果[`声明...处理程序`](declare-handler.html)语句不存在，MySQL 将采取默认操作 (`出口`) 在第二个之后[`插入`](insert.html)失败的原因是`首要的关键`约束，和`选择@x`会回来的`2`.

要忽略一个条件，声明一个`继续`处理程序并将其与空块相关联。例如：

```
DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;
```

块标签的范围不包括块内声明的处理程序的代码。因此，与处理程序关联的语句不能使用[`迭代`](iterate.html)要么[`离开`](leave.html)引用包含处理程序声明的块的标签。考虑以下示例，其中[`重复`](repeat.html)块的标签为`重试`：

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

这`重试`标签在范围内[`如果`](if.html)块内的语句。它不在适用范围内`继续`处理程序，因此那里的引用无效并导致错误：

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

要避免在处理程序中引用外部标签，请使用以下策略之一：

-   要离开区块，请使用`出口`处理程序。如果不需要块清理，则[`开始...结束`](begin-end.html)处理程序主体可以为空：

    ```
    DECLARE EXIT HANDLER FOR SQLWARNING BEGIN END;
    ```

    否则，将清理语句放在处理程序主体中：

    ```
    DECLARE EXIT HANDLER FOR SQLWARNING
      BEGIN
        block cleanup statements
      END;
    ```

-   要继续执行，请在`继续`可以在封闭块中检查的处理程序以确定是否调用了处理程序。以下示例使用变量`完毕`以此目的：

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