Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  ...  /  Scope Rules for Handlers

15.6.7.6 处理程序的作用域规则

存储程序可能包含处理程序,以便在程序中出现某些条件时被调用。每个处理程序的适用性取决于其在程序定义中的位置和它处理的条件:

  • BEGIN ... END 块中声明的处理程序仅在该块中的 SQL 语句后生效。如果处理程序本身引发了条件,它不能处理该条件,也不能处理块中的其他处理程序。在以下示例中,处理程序 H1H2 适用于语句 stmt1stmt2 所引发的条件。但是, neither H1 nor H2 适用于处理程序 H1H2 的主体中的条件。

    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 值或条件名称。一般的处理程序是为 SQLWARNINGSQLEXCEPTIONNOT FOUND 类的条件。条件的特异性与条件优先级相关,如后面所述。

可以在不同的作用域中声明多个处理程序,每个处理程序具有不同的特异性。例如,可能在外层块中有一个特定的 MySQL 错误代码处理程序,而在内层块中有一个一般的 SQLWARNING 处理程序。或者,在同一个块中可能有一个特定的 MySQL 错误代码处理程序和一个一般的 SQLWARNING 处理程序。

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

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

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

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

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

处理程序选择规则的一个推论是,如果多个适用的处理程序出现在不同的作用域中,那么具有最 local 作用域的处理程序优先于外层作用域中的处理程序,甚至优先于那些具有更具体条件的处理程序。

如果在条件出现时没有适用的处理程序,采取的操作取决于条件的类别:

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

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

  • 对于 NOT FOUND 条件,如果条件是正常引发的,那么操作是 CONTINUE。如果它是由 SIGNALRESIGNAL 引发的,那么操作是 EXIT

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

该过程包含两个处理程序,一个是特定的 SQLSTATE 值 ('42S02'),该值在尝试删除不存在的表时出现,另一个是 general 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 处理程序更 general:

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'