• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • 处理程序的范围规则

    存储的程序可以包括在程序中发生某些条件时要调用的处理程序。每个处理程序的适用性取决于其在程序定义中的位置以及其处理的条件:

    • BEGIN ... END块中声明的处理程序仅适用于该块中的处理程序声明之后的SQL语句。如果处理程序本身引发了一个条件,则它将无法处理该条件,该块中声明的任何其他处理程序也将无法处理。在以下示例中,处理程序H1H2适用于语句stmt1和引发的条件stmt2。但是H1也不H2存在于H1或体内提出的条件的范围H2

      BEGIN -- outer block
        DECLARE EXIT HANDLER FOR ...;  -- handler H1
        DECLARE EXIT HANDLER FOR ...;  -- handler H2
        stmt1;
        stmt2;
      END;
      
    • 处理程序仅在声明它的块的范围内,并且对于该块外部发生的条件无法激活。在以下示例中,处理程序H1stmt1内部块的作用域中,而stmt2在外部块的作用域中:

      BEGIN -- outer block
        BEGIN -- inner block
          DECLARE EXIT HANDLER FOR ...;  -- handler H1
          stmt1;
        END;
        stmt2;
      END;
      
    • 处理程序可以是特定的,也可以是一般的。特定的处理程序用于MySQL错误代码,SQLSTATE值或条件名称。一般的处理程序是用于在一个状态SQLWARNINGSQLEXCEPTIONNOT FOUND类。条件特异性与条件优先级相关,如下所述。

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

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

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

    处理程序选择规则的一个含义是,如果多个适用的处理程序出现在不同的作用域中,则具有最局部作用域的处理程序将优先于外部作用域中的处理程序,甚至优先于更特定条件的处理程序。

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

    • 对于SQLEXCEPTION条件,存储程序终止于引发条件的语句,就像有一个EXIT处理程序一样。如果该程序是由另一个存储程序调用的,则调用程序将使用应用于其自身处理程序的处理程序选择规则来处理该条件。
    • 对于SQLWARNING条件,程序将继续执行,就像有一个CONTINUE处理程序一样。
    • 对于NOT FOUND条件,如果条件正常升高,则操作为CONTINUE。如果是由SIGNAL或提出的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'
    

    上篇:SIGNAL语句

    下篇:MySQL诊断区域