Documentation Home
MySQL 8.0 参考手册  / 第 13 章 SQL 语句  / 13.6 复合语句语法  / 13.6.7 条件处理  /  13.6.7.6 处理程序的范围规则

13.6.7.6 处理程序的范围规则

存储的程序可以包括处理程序,当程序中出现某些条件时将调用该处理程序。每个处理程序的适用性取决于它在程序定义中的位置以及它处理的一个或多个条件:

  • BEGIN ... END块中声明的处理程序仅在块中处理程序声明之后的 SQL 语句的范围内。如果处理程序本身引发条件,则它无法处理该条件,块中声明的任何其他处理程序也无法处理。在以下示例中,处理程序H1和 在语句和 H2引发的条件范围内。但是 nor都不在 or正文中提出的条件的范围内。 stmt1stmt2H1H2H1H2

    BEGIN -- outer block
      DECLARE EXIT HANDLER FOR ...;  -- handler H1
      DECLARE EXIT HANDLER FOR ...;  -- handler H2
      stmt1;
      stmt2;
    END;
  • 处理程序仅在声明它的块的范围内,并且不能为该块之外发生的条件激活。在以下示例中,处理程序 H1在内部块的范围 stmt1内,但不在stmt2外部块的范围内:

    BEGIN -- outer block
      BEGIN -- inner block
        DECLARE EXIT HANDLER FOR ...;  -- handler H1
        stmt1;
      END;
      stmt2;
    END;
  • 处理程序可以是特定的或通用的。特定的处理程序用于 MySQL 错误代码、SQLSTATE值或条件名称。通用处理程序用于 、 或 类中SQLWARNINGSQLEXCEPTION条件NOT FOUND。条件特异性与条件优先级有关,如后所述。

可以在不同的范围内声明多个处理程序并具有不同的特性。例如,外部块中可能有一个特定的 MySQL 错误代码处理 SQLWARNING程序,内部块中可能有一个通用处理程序。SQLWARNING或者在同一个块中 可能有针对特定 MySQL 错误代码和通用类的处理程序。

处理程序是否被激活不仅取决于它自己的范围和条件值,还取决于存在的其他处理程序。BEGIN ... END当存储程序中出现条件时,服务器会在当前范围(当前块)中搜索适用的处理程序 。如果没有适用的处理程序,则继续向外搜索每个连续包含范围(块)中的处理程序。当服务器在给定范围内找到一个或多个适用的处理程序时,它会根据条件优先级在其中进行选择:

  • MySQL 错误代码处理程序优先于 SQLSTATE值处理程序。

  • SQLSTATE值处理程序优先于一般 的SQLWARNINGSQLEXCEPTIONNOT FOUND处理程序。

  • SQLEXCEPTION处理程序优先于 处理SQLWARNING程序。

  • 可以有多个具有相同优先级的适用处理程序。例如,一条语句可以生成多个具有不同错误代码的警告,每个错误代码都存在一个特定于错误的处理程序。在这种情况下,服务器激活哪个处理程序的选择是不确定的,并且可能会根据条件发生的情况而改变。

处理程序选择规则的一个含义是,如果多个适用的处理程序出现在不同的范围内,则具有最本地范围的处理程序优先于外部范围中的处理程序,甚至超过那些更具体条件的处理程序。

如果在条件发生时没有合适的处理程序,则采取的操作取决于条件的类别:

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

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

  • 对于NOT FOUND条件,如果条件正常出现,则操作为 CONTINUE。如果它是由 SIGNALor 引发的RESIGNAL,则操作为 EXIT

以下示例演示了 MySQL 如何应用处理程序选择规则。

此过程包含两个处理程序,一个用于 尝试删除不存在的表时出现的特定SQLSTATE值 ( ),另一个用于一般类: '42S02'SQLEXCEPTION

CREATE PROCEDURE p1()
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
    SELECT 'SQLSTATE handler was activated' AS msg;
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
    SELECT 'SQLEXCEPTION handler was activated' AS msg;

  DROP TABLE test.t;
END;

两个处理程序都在同一个块中声明并且具有相同的范围。但是,SQLSTATE处理程序优先于SQLEXCEPTION处理程序,因此如果表t不存在,该 DROP TABLE语句会引发一个条件来激活SQLSTATE 处理程序:

mysql> CALL p1();
+--------------------------------+
| msg                            |
+--------------------------------+
| SQLSTATE handler was activated |
+--------------------------------+

此过程包含相同的两个处理程序。但是这一次,DROP TABLE语句和 SQLEXCEPTION处理程序位于相对于处理程序的内部块中SQLSTATE

CREATE PROCEDURE p2()
BEGIN -- outer block
    DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
      SELECT 'SQLSTATE handler was activated' AS msg;
  BEGIN -- inner block
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
      SELECT 'SQLEXCEPTION handler was activated' AS msg;

    DROP TABLE test.t; -- occurs within inner block
  END;
END;

在这种情况下,更接近条件发生位置的处理程序优先。SQLEXCEPTION处理程序激活,即使它比处理程序更通用 SQLSTATE

mysql> CALL p2();
+------------------------------------+
| msg                                |
+------------------------------------+
| SQLEXCEPTION handler was activated |
+------------------------------------+

在此过程中,其中一个处理程序在语句范围内的块中DROP TABLE声明:

CREATE PROCEDURE p3()
BEGIN -- outer block
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
    SELECT 'SQLEXCEPTION handler was activated' AS msg;
  BEGIN -- inner block
    DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
      SELECT 'SQLSTATE handler was activated' AS msg;
  END;

  DROP TABLE test.t; -- occurs within outer block
END;

只有SQLEXCEPTION处理程序适用,因为另一个处理程序不在引发的条件的范围内 DROP TABLE

mysql> CALL p3();
+------------------------------------+
| msg                                |
+------------------------------------+
| SQLEXCEPTION handler was activated |
+------------------------------------+

在此过程中,两个处理程序都在语句范围内的块中DROP TABLE 声明:

CREATE PROCEDURE p4()
BEGIN -- outer block
  BEGIN -- inner block
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
      SELECT 'SQLEXCEPTION handler was activated' AS msg;
    DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
      SELECT 'SQLSTATE handler was activated' AS msg;
  END;

  DROP TABLE test.t; -- occurs within outer block
END;

两个处理程序都不适用,因为它们不在 DROP TABLE. 语句引发的条件未得到处理并因错误而终止过程:

mysql> CALL p4();
ERROR 1051 (42S02): Unknown table 'test.t'