文档首页
MySQL 9.0 参考手册
相关文档 下载本手册
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
手册页 (TGZ) - 258.2Kb
手册页 (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 9.0 参考手册  /  ...  /  处理程序的作用域规则

15.6.7.6 处理程序的作用域规则

存储程序可以包含处理程序,这些处理程序在程序中发生某些条件时会被调用。每个处理程序的适用性取决于它在程序定义中的位置以及它处理的条件。

  • BEGIN ... END 块中声明的处理程序仅对块中处理程序声明之后的 SQL 语句有效。如果处理程序本身引发了条件,它不能处理该条件,块中声明的其他处理程序也不能处理该条件。在下面的示例中,处理程序 H1H2 对语句 stmt1stmt2 引发的条件有效。但 H1H2 都不对 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 处理程序。

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

处理程序选择规则的一个含义是,如果在不同作用域中存在多个适用处理程序,则具有最局部作用域的处理程序优先于外层作用域的处理程序,即使是针对更特定条件的处理程序。

如果条件发生时没有合适的处理程序,采取的行动将取决于条件的类别。

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

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

  • 对于 NOT FOUND 条件,如果条件是正常引发的,则操作为 CONTINUE。如果它是通过 SIGNALRESIGNAL 引发的,则操作为 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'